# Database Schema

This document provides an overview of the Quizzical Beats database schema, including tables, relationships, and key fields.

## Entity Relationship Diagram

The following diagram illustrates the relationships between the main entities in Quizzical Beats:

```
+---------------+       +---------------+       +---------------+
|    User       |       |    Round      |       |    Song       |
+---------------+       +---------------+       +---------------+
| id            |<----->| id            |       | id            |
| username      |       | name          |       | title         |
| email         |       | round_type    |       | artist        |
| password_hash |       | songs         |-------| spotify_id    |
| is_admin      |       | round_criteria|       | deezer_id     |
| roles         |----+  | created_at    |       | isrc          |
| auth_provider |    |  | updated_at    |       | preview_url   |
| oauth_tokens  |    |  | mp3_generated |       | cover_url     |
+---------------+    |  | pdf_generated |       | tags          |----+
      ^              |  +---------------+       | audio_features|    |
      |              |                          +---------------+    |
      |              |                                  ^            |
      |              v                                  |            |
+---------------+  +---------------+       +---------------+         |
| UserPreferences|  |    Role      |       | RoundExport   |         |
+---------------+  +---------------+       +---------------+         |
| id            |  | id            |       | id            |         |
| user_id       |  | name          |       | round_id      |         |
| default_tts   |  | description   |       | user_id       |         |
| enable_intro  |  +---------------+       | export_type   |         |
| theme         |                          | timestamp     |         |
+---------------+                          | destination   |         |
                                           +---------------+         |
                                                                     |
+---------------+                          +---------------+         |
| SystemSetting |                          |     Tag       |<--------+
+---------------+                          +---------------+
| id            |                          | id            |
| key           |                          | name          |
| value         |                          | created_at    |
+---------------+                          +---------------+
```

## Tables

### User

The `User` table stores user account information and authentication details.

| Column                | Type         | Description                                      |
|-----------------------|--------------|--------------------------------------------------|
| id                    | Integer      | Primary key                                      |
| username              | String(80)   | User's display name                              |
| email                 | String(120)  | User's email address                             |
| password_hash         | String(255)  | Hashed password (nullable for OAuth-only users)  |
| first_name            | String(50)   | User's first name                                |
| last_name             | String(50)   | User's last name                                 |
| active                | Boolean      | Account active status                            |
| is_admin              | Boolean      | Administrator privileges flag                    |
| created_at            | DateTime     | Account creation timestamp                       |
| last_login            | DateTime     | Last login timestamp                             |
| reset_token           | String(100)  | Password reset token                             |
| reset_token_expiry    | DateTime     | Token expiration time                            |
| auth_provider         | String(20)   | Authentication provider (local, google, etc.)    |
| spotify_id            | String(100)  | Spotify user ID                                  |
| spotify_token         | Text         | Spotify access token                             |
| spotify_refresh_token | Text         | Spotify refresh token                            |
| spotify_token_expiry  | DateTime     | Spotify token expiration                         |
| google_id             | String(100)  | Google user ID                                   |
| google_token          | Text         | Google access token                              |
| google_refresh_token  | Text         | Google refresh token                             |
| authentik_id          | String(100)  | Authentik user ID                                |
| authentik_token       | Text         | Authentik access token                           |
| authentik_refresh_token | Text       | Authentik refresh token                          |
| dropbox_id            | String(100)  | Dropbox user ID                                  |
| dropbox_token         | Text         | Dropbox access token                             |
| dropbox_refresh_token | Text         | Dropbox refresh token                            |
| dropbox_token_expiry  | DateTime     | Dropbox token expiration                         |
| dropbox_export_path   | String(255)  | User's preferred Dropbox export folder           |
| intro_mp3             | String(255)  | Custom intro MP3 path                            |
| outro_mp3             | String(255)  | Custom outro MP3 path                            |
| replay_mp3            | String(255)  | Custom replay MP3 path                           |

### UserPreferences

The `UserPreferences` table stores user-specific settings.

| Column               | Type         | Description                                      |
|----------------------|--------------|--------------------------------------------------|
| id                   | Integer      | Primary key                                      |
| user_id              | Integer      | Foreign key to User                              |
| default_tts_service  | String(32)   | Default text-to-speech service (polly, etc.)     |
| enable_intro         | Boolean      | Whether to enable intro sound                    |
| theme                | String(16)   | UI theme preference (light, dark)                |

### Role

The `Role` table defines user roles for permission management.

| Column      | Type         | Description                                      |
|-------------|--------------|--------------------------------------------------|
| id          | Integer      | Primary key                                      |
| name        | String(50)   | Role name                                        |
| description | String(255)  | Role description                                 |

### user_roles

The `user_roles` table is an association table linking users to roles.

| Column      | Type         | Description                                      |
|-------------|--------------|--------------------------------------------------|
| user_id     | Integer      | Foreign key to User                              |
| role_id     | Integer      | Foreign key to Role                              |

### Song

The `Song` table stores detailed information about music tracks from various sources.

| Column                | Type         | Description                                     |
|-----------------------|--------------|-------------------------------------------------|
| id                    | Integer      | Primary key                                     |
| spotify_id            | String(100)  | Spotify track ID                                |
| deezer_id             | Integer      | Deezer track ID                                 |
| isrc                  | String(20)   | International Standard Recording Code           |
| title                 | String(200)  | Song title                                      |
| artist                | String(200)  | Artist name                                     |
| album_name            | String(200)  | Album name                                      |
| genre                 | String(100)  | Music genre                                     |
| year                  | Integer      | Release year                                    |
| preview_url           | String(500)  | Primary audio preview URL                       |
| cover_url             | String(500)  | Primary album cover URL                         |
| spotify_preview_url   | String(500)  | Spotify-specific preview URL                    |
| deezer_preview_url    | String(500)  | Deezer-specific preview URL                     |
| apple_preview_url     | String(500)  | Apple Music preview URL                         |
| youtube_preview_url   | String(500)  | YouTube preview URL                             |
| spotify_cover_url     | String(500)  | Spotify cover image URL                         |
| deezer_cover_url      | String(500)  | Deezer cover image URL                          |
| apple_cover_url       | String(500)  | Apple Music cover image URL                     |
| popularity            | Integer      | Popularity score (0-100)                        |
| used_count            | Integer      | Number of times used in rounds                  |
| source                | String(20)   | Data source (spotify, deezer, acrcloud)         |
| import_date           | DateTime     | When the song was imported                      |
| added_at              | DateTime     | When the song was added                         |
| last_used             | DateTime     | When the song was last used                     |
| metadata_sources      | String(500)  | Comma-separated list of metadata sources        |
| acousticness          | Float        | Spotify audio feature - acousticness (0.0-1.0)  |
| danceability          | Float        | Spotify audio feature - danceability (0.0-1.0)  |
| energy                | Float        | Spotify audio feature - energy (0.0-1.0)        |
| instrumentalness      | Float        | Spotify audio feature - instrumentalness        |
| key                   | Integer      | Spotify audio feature - musical key             |
| liveness              | Float        | Spotify audio feature - liveness (0.0-1.0)      |
| loudness              | Float        | Spotify audio feature - loudness (dB)           |
| mode                  | Integer      | Spotify audio feature - modality (major/minor)  |
| speechiness           | Float        | Spotify audio feature - speechiness (0.0-1.0)   |
| tempo                 | Float        | Spotify audio feature - tempo (BPM)             |
| time_signature        | Integer      | Spotify audio feature - time signature          |
| valence               | Float        | Spotify audio feature - valence (0.0-1.0)       |
| duration_ms           | Integer      | Track duration in milliseconds                  |
| analysis_url          | String(500)  | URL to full audio analysis                      |
| additional_data       | Text         | Additional data as JSON                         |

### Tag

The `Tag` table stores tags for categorizing songs.

| Column      | Type         | Description                                      |
|-------------|--------------|--------------------------------------------------|
| id          | Integer      | Primary key                                      |
| name        | String(50)   | Tag name                                         |
| created_at  | DateTime     | Creation timestamp                               |

### SongTag

The `SongTag` table links songs to tags.

| Column      | Type         | Description                                      |
|-------------|--------------|--------------------------------------------------|
| song_id     | Integer      | Foreign key to Song                              |
| tag_id      | Integer      | Foreign key to Tag                               |
| created_at  | DateTime     | When the tag was applied                         |

### Round

The `Round` table stores music quiz rounds.

| Column                | Type         | Description                                      |
|-----------------------|--------------|--------------------------------------------------|
| id                    | Integer      | Primary key                                      |
| name                  | String(200)  | Round name                                       |
| round_type            | String(50)   | Type of round (genre, decade, etc.)              |
| round_criteria_used   | String(500)  | Criteria used to generate the round              |
| songs                 | Text         | JSON string of song IDs in order                 |
| genre                 | String(100)  | Genre of the round (if applicable)               |
| decade                | String(10)   | Decade of the round (if applicable)              |
| tag                   | String(50)   | Tag of the round (if applicable)                 |
| created_at            | DateTime     | Creation timestamp                               |
| updated_at            | DateTime     | Last update timestamp                            |
| mp3_generated         | Boolean      | Flag indicating if MP3 has been generated        |
| pdf_generated         | Boolean      | Flag indicating if PDF has been generated        |
| last_generated_at     | DateTime     | When files were last generated                   |

### RoundExport

The `RoundExport` table tracks exports of rounds to various destinations.

| Column        | Type         | Description                                      |
|---------------|--------------|--------------------------------------------------|
| id            | Integer      | Primary key                                      |
| round_id      | Integer      | Foreign key to Round                             |
| user_id       | Integer      | Foreign key to User                              |
| export_type   | String(20)   | Export type (dropbox, email, etc.)               |
| timestamp     | DateTime     | Export timestamp                                 |
| destination   | String(500)  | Destination (path, email, etc.)                  |
| include_mp3s  | Boolean      | Whether MP3s were included                       |
| status        | String(20)   | Export status (success, failed)                  |
| error_message | Text         | Error message if export failed                   |

### SystemSetting

The `SystemSetting` table stores application-wide settings.

| Column      | Type         | Description                                      |
|-------------|--------------|--------------------------------------------------|
| id          | Integer      | Primary key                                      |
| key         | String(64)   | Setting key                                      |
| value       | Text         | Setting value                                    |

## Key Relationships

### User Relationships

- **User → UserPreferences**: One-to-one. A user has one set of preferences.
- **User ↔ Roles**: Many-to-many through user_roles. A user can have multiple roles, and a role can be assigned to multiple users.
- **User → RoundExports**: One-to-many. A user can create multiple exports.

### Song Relationships

- **Song ↔ Tags**: Many-to-many through SongTag. A song can have multiple tags, and a tag can be applied to multiple songs.
- **Song → Rounds**: Many-to-many (implicit). Songs are referenced in the Round.songs field as a JSON string of IDs.

### Round Relationships

- **Round → RoundExports**: One-to-many. A round can have multiple exports.
- **Round → Songs**: Many-to-many (implicit). A round contains multiple songs referenced by ID.

## Data Model Features

### OAuth Integration

The User model integrates OAuth provider information directly:
- Support for Spotify, Google, Authentik and Dropbox OAuth providers
- Token storage and refresh token functionality
- Provider-specific user IDs

### Audio Features

The Song model includes detailed audio features from Spotify:
- Acoustic characteristics (acousticness, instrumentalness)
- Rhythmic characteristics (tempo, time_signature)
- Mood characteristics (valence, energy, danceability)
- Technical characteristics (loudness, key, mode)

### Multi-Source Integration

Songs can be imported from multiple sources:
- Spotify API
- Deezer API
- ACRCloud identification service
- Each song stores source-specific IDs and URLs

### Tagging System

The tagging system allows flexible organization:
- Songs can be tagged for easier categorization
- Tags provide a way to group songs by custom criteria

## Data Migrations

The database schema evolves over time through migrations. Migration scripts are stored in the `migrations/` directory:

- `add_preview_urls.py`: Added Song.preview_url field
- `add_song_fields.py`: Added additional metadata fields to Song
- `add_spotify_audio_features.py`: Added audio analysis data
- `add_oauth_providers.py`: Extended OAuth provider support
- `add_tag_system.py`: Added tagging functionality
- `add_dropbox_oauth.py`: Added Dropbox OAuth support
- `add_dropbox_export_path.py`: Added export path tracking