# Sonic Cloud - Project Documentation **Version**: 0.1.0 **Type**: Music Platform for Musicians and Listeners --- ## Executive Summary ### What is Sonic Cloud? Sonic Cloud is a modern music platform that connects musicians with listeners. Think of it as a place where independent artists can upload their music, organize it into albums, and share it with the world - while listeners can discover new music, create playlists, and follow their favorite artists. **Key Capabilities**: - Musicians upload and manage their songs and albums - Listeners discover trending music and new releases - Everyone can create and share custom playlists - Built-in audio player with waveform visualization - Search across all songs, artists, and albums ### Who is it for? **Musicians**: Upload your tracks, organize them into albums, build your artist profile, and track how many plays your music gets. **Labels**: Manage multiple artists under your label, invite new talent, and view collective statistics. **Listeners**: Discover new music by genre, create playlists, follow artists, and share your favorite songs. --- ## Quick Start ### Installation ```bash # Install dependencies npm install # Set up database npx prisma generate npx prisma db push # Start development server npm run dev ``` Open [http://localhost:3000](http://localhost:3000) in your browser. ### First Steps 1. **Register an account** at `/register` 2. **Become an artist** by creating an artist profile 3. **Upload your first song** using the upload form 4. **Create a playlist** to organize music you love 5. **Search and discover** trending songs and new releases --- ## Architecture Overview ### System Architecture ``` ┌─────────────────────────────────────────────────────────────────┐ │ USER BROWSER │ │ (React 19 + Next.js 16) │ └────────────────────────────┬────────────────────────────────────┘ │ │ HTTP Requests ▼ ┌─────────────────────────────────────────────────────────────────┐ │ NEXT.JS APP ROUTER │ │ ┌──────────────────┐ ┌──────────────────┐ │ │ │ Pages (SSR) │ │ API Routes │ │ │ │ - Home │ │ - Auth │ │ │ │ - Artist │ │ - Songs │ │ │ │ - Album │ │ - Playlists │ │ │ │ - Playlist │ │ - Search │ │ │ │ - Profile │ │ - Share │ │ │ └──────────────────┘ └──────────────────┘ │ └────────────────────────────┬────────────────────────────────────┘ │ │ Prisma ORM ▼ ┌─────────────────────────────────────────────────────────────────┐ │ SQLITE DATABASE │ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │ │ Users │ │ Artists │ │ Songs │ │ Playlists│ │ │ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │ │ Albums │ │ Labels │ │ Genres │ │ Shares │ │ │ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │ └─────────────────────────────────────────────────────────────────┘ ``` ### Data Flow ``` User Action → React Component → API Endpoint → Prisma ORM → SQLite │ ▼ User Sees Update ← React Refresh ← JSON Response ← Data Query ───┘ ``` ### Technology Stack | Layer | Technology | Purpose | |-------|------------|---------| | **Frontend** | React 19.2.1 | Interactive user interface | | **Framework** | Next.js 16.0.10 | Server-side rendering, routing, API | | **Styling** | Tailwind CSS 4 | Responsive, utility-first design | | **Language** | TypeScript 5 | Type safety and better code quality | | **Database** | SQLite | Lightweight, file-based storage | | **ORM** | Prisma 5.22.0 | Type-safe database access | | **Authentication** | JWT + bcryptjs | Secure user sessions |
🔧 Technical Details - Framework Decisions **Why Next.js?** - File-based routing simplifies page creation - API routes eliminate need for separate backend - Server-side rendering improves SEO and performance - React 19 supports latest concurrent features **Why SQLite?** - Zero configuration for development - Single file database for easy deployment - Sufficient performance for small-to-medium scale - Easy migration to PostgreSQL/MySQL later if needed **Why Prisma?** - Type-safe database queries prevent runtime errors - Schema-first approach documents data model - Automatic migration generation - Built-in connection pooling
--- ## Features ### For Musicians (Artists) #### Upload and Manage Songs Upload audio files with metadata like title, genre, cover art, and description. Your songs are stored with unique IDs and can be updated or deleted at any time.
🔧 Technical Details - Song Upload Flow ```typescript POST /api/songs/upload Headers: { Authorization: "Bearer " } Body: { title: string, artistId: string, albumId?: string, audioUrl: string, // URL to audio file coverImageUrl?: string, duration: number, // in seconds isPublic: boolean, genres: string[] // genre slugs } ``` **Process**: 1. Validate JWT token → get authenticated user 2. Verify user owns the artist profile 3. Create Song record in database 4. Create SongGenre junction records 5. Return song with ID and metadata **Validation**: - Duration must be > 0 - Audio URL format validation - Genre slugs must exist in Genre table
#### Organize Albums Group songs into albums, EPs, or singles. Each album has a release date, cover art, and track listing that you control.
🔧 Technical Details - Album Structure ```typescript // Album model fields { id: string, // UUID artistId: string, // FK to Artist title: string, releaseDate: Date, albumType: "ALBUM" | "EP" | "SINGLE", coverImageUrl?: string, description?: string, songs: Song[] // hasMany relation } ``` **Album Types**: - **ALBUM**: 8+ tracks, typically 30-60 minutes - **EP**: 3-7 tracks, typically 15-30 minutes - **SINGLE**: 1-2 tracks
#### Artist Profile Create a professional profile with bio, avatar, verified badge, and links to your label (if applicable). Track your total plays across all songs. #### Analytics See how many times each song has been played. Monitor which songs are trending and which need promotion.
🔧 Technical Details - Play Tracking ```typescript POST /api/songs/{id}/play // Updates play count atomically await prisma.song.update({ where: { id: songId }, data: { playCount: { increment: 1 } } }); ``` **Note**: Play count is incremented on each play request. For production, consider: - IP-based rate limiting to prevent abuse - Session tracking to count unique plays - Analytics aggregation for performance
--- ### For Labels #### Manage Multiple Artists Create a label profile and invite artists to join your roster. View all artists under your label in one dashboard. #### Label Statistics See aggregate stats across all your artists: total songs, albums, and cumulative play counts.
🔧 Technical Details - Label Stats API ```typescript GET /api/labels/{id}/stats Response: { artistCount: number, songCount: number, albumCount: number, totalPlays: number } ``` **Calculation**: - Artist count: Direct count of Artist records with labelId - Song/Album count: Sum across all label artists - Total plays: Aggregate playCount from all songs by label artists
#### Invitation System Send invitations to artists. They can accept or decline. Track invitation status (pending, accepted, declined, expired). --- ### For Listeners #### Discover Music Browse trending songs (sorted by play count) and new releases (sorted by upload date). Filter by genre to find music you love.
🔧 Technical Details - Discovery Queries ```typescript // Trending songs GET /api/discover/trending?limit=20 // SQL equivalent SELECT * FROM Song WHERE isPublic = true ORDER BY playCount DESC LIMIT 20; // New releases GET /api/discover/new-releases?limit=20 // SQL equivalent SELECT * FROM Song WHERE isPublic = true ORDER BY createdAt DESC LIMIT 20; ```
#### Create Playlists Make custom playlists with any songs on the platform. Control playlist privacy (public or private). Reorder songs by dragging. #### Search Everything Type a query and search across songs (title), artists (name), and albums (title) simultaneously.
🔧 Technical Details - Search Implementation ```typescript GET /api/search?q=rock // Searches across three tables Songs: WHERE title LIKE '%rock%' OR description LIKE '%rock%' Artists: WHERE name LIKE '%rock%' OR bio LIKE '%rock%' Albums: WHERE title LIKE '%rock%' OR description LIKE '%rock%' Response: { songs: Song[], artists: Artist[], albums: Album[] } ``` **Current Limitations**: - Case-insensitive substring matching only - No relevance scoring - No fuzzy matching **Future Enhancements**: - Full-text search engine (Algolia, Elasticsearch) - Relevance ranking by play count and recency - Typo tolerance and autocomplete
#### Audio Player Play songs with a fixed bottom player that follows you across pages. Features include: - Play/pause, next/previous track - Visual waveform with seek functionality - Volume control and mute - Shuffle and repeat modes --- ### For Everyone #### Share Content Generate shareable links for songs, playlists, and albums. Track how many times your share links are clicked.
🔧 Technical Details - Share Link Generation ```typescript POST /api/share/song/{id} // Creates Share record { id: string, type: "SONG" | "PLAYLIST" | "ALBUM", targetId: string, // ID of shared content token: string, // nanoid(10) - short unique code userId?: string, // Who created the share clickCount: number, createdAt: Date } // Returns shareable URL https://sonic-cloud.app/s/{token} ``` **Share Token Format**: 10-character nanoid (URL-safe, lowercase + numbers) **Click Tracking**: Each time `/s/{token}` is visited, clickCount increments.
#### Genre System Browse music by genre. Each genre has a name, slug (URL-friendly), description, and visual color code. #### User Profiles View other users' public playlists and activity. Update your own profile with display name, bio, and avatar. --- ## API Reference The platform exposes 40 RESTful API endpoints across 8 functional domains. ### Authentication (`/api/auth`) | Endpoint | Method | Auth Required | Description | |----------|--------|---------------|-------------| | `/auth/register` | POST | No | Create new user account | | `/auth/login` | POST | No | Authenticate and receive JWT | | `/auth/forgot-password` | POST | No | Request password reset email | | `/auth/reset-password` | POST | No | Reset password with token |
🔧 Technical Details - Authentication Flow **Registration**: ```typescript POST /api/auth/register Body: { email: string, password: string, // Min 8 chars username: string, // Unique, 3-20 chars displayName?: string } Response: { user: { id, email, username, role }, token: string // JWT valid for 7 days } ``` **Login**: ```typescript POST /api/auth/login Body: { email: string, password: string } Response: { user: { id, email, username, role }, token: string } ``` **JWT Payload**: ```typescript { userId: string, email: string, role: "USER" | "ADMIN", iat: number, // issued at exp: number // expires at (7 days) } ``` **Password Hashing**: bcryptjs with 10 salt rounds **Token Validation**: All protected routes verify JWT via `Authorization: Bearer ` header
--- ### Users (`/api/users`) | Endpoint | Method | Auth Required | Description | |----------|--------|---------------|-------------| | `/users/me` | GET | Yes | Get current user profile | | `/users/me` | PUT | Yes | Update profile (displayName, bio, avatarUrl) | --- ### Artists (`/api/artists`) | Endpoint | Method | Auth Required | Description | |----------|--------|---------------|-------------| | `/artists` | POST | Yes | Create artist profile for current user | | `/artists/{id}` | GET | No | Get artist details with stats | | `/artists/{id}` | PUT | Yes | Update artist profile (owner only) | | `/artists/{id}/songs` | GET | No | Get all public songs by artist | | `/artists/{id}/albums` | GET | No | Get all albums by artist |
🔧 Technical Details - Artist Endpoints **Create Artist**: ```typescript POST /api/artists Body: { name: string, bio?: string, avatarUrl?: string, websiteUrl?: string } // Automatically generates slug from name // Associates with authenticated userId ``` **Get Artist**: ```typescript GET /api/artists/{id} Response: { id, name, slug, bio, avatarUrl, verified, userId, labelId, _count: { songs: number, albums: number }, label?: { id, name, slug } } ``` **Authorization**: Only artist owner can update their profile
--- ### Songs (`/api/songs`) | Endpoint | Method | Auth Required | Description | |----------|--------|---------------|-------------| | `/songs/upload` | POST | Yes | Upload new song (artist only) | | `/songs/{id}` | GET | No | Get song details (respects privacy) | | `/songs/{id}` | PUT | Yes | Update song metadata (owner only) | | `/songs/{id}` | DELETE | Yes | Delete song (owner only) | | `/songs/{id}/play` | POST | No | Increment play count | --- ### Albums (`/api/albums`) | Endpoint | Method | Auth Required | Description | |----------|--------|---------------|-------------| | `/albums` | POST | Yes | Create album (artist only) | | `/albums/{id}` | GET | No | Get album with all songs | | `/albums/{id}` | PUT | Yes | Update album (owner only) | | `/albums/{id}` | DELETE | Yes | Delete album (owner only) | --- ### Playlists (`/api/playlists`) | Endpoint | Method | Auth Required | Description | |----------|--------|---------------|-------------| | `/playlists` | GET | Yes | Get current user's playlists | | `/playlists` | POST | Yes | Create new playlist | | `/playlists/{id}` | GET | No | Get playlist (respects privacy) | | `/playlists/{id}` | PUT | Yes | Update playlist (owner only) | | `/playlists/{id}` | DELETE | Yes | Delete playlist (owner only) | | `/playlists/{id}/songs` | POST | Yes | Add song to playlist | | `/playlists/{id}/reorder` | PUT | Yes | Reorder songs in playlist |
🔧 Technical Details - Playlist Reordering ```typescript PUT /api/playlists/{id}/reorder Body: { songIds: string[] // Ordered array of song IDs } // Updates position field for each PlaylistSong junction record for (let i = 0; i < songIds.length; i++) { await prisma.playlistSong.updateMany({ where: { playlistId: id, songId: songIds[i] }, data: { position: i } }); } ``` **Position Indexing**: 0-based integer positions for stable ordering
--- ### Discovery (`/api/discover`) | Endpoint | Method | Auth Required | Description | |----------|--------|---------------|-------------| | `/discover/trending` | GET | No | Get trending songs by play count | | `/discover/new-releases` | GET | No | Get newest public songs | | `/discover/genres` | GET | No | Get all genres with song counts | | `/discover/genres/{slug}` | GET | No | Get songs in specific genre | --- ### Labels (`/api/labels`) | Endpoint | Method | Auth Required | Description | |----------|--------|---------------|-------------| | `/labels` | POST | Yes | Create label profile | | `/labels/{id}` | GET | No | Get label details with artists | | `/labels/{id}` | PUT | Yes | Update label (owner only) | | `/labels/{id}/stats` | GET | No | Get aggregate label statistics | | `/labels/{id}/artists` | GET | No | Get all artists under label | --- ### Search (`/api/search`) | Endpoint | Method | Auth Required | Description | |----------|--------|---------------|-------------| | `/search?q={query}` | GET | No | Search songs, artists, albums | --- ### Sharing (`/api/share`) | Endpoint | Method | Auth Required | Description | |----------|--------|---------------|-------------| | `/share/song/{id}` | POST | No | Create shareable link for song | | `/share/playlist/{id}` | POST | No | Create shareable link for playlist | | `/share/album/{id}` | POST | No | Create shareable link for album | | `/share/{token}` | GET | No | Resolve share link to content | | `/share/{token}/click` | POST | No | Track share link click | --- ## Data Models The database uses 10 core tables to represent the music platform. ### User Base account entity for authentication and profile. **Key Fields**: - `id` (UUID): Primary key - `email` (string): Unique, lowercase, used for login - `username` (string): Unique, 3-20 characters - `displayName` (string): Optional public name - `passwordHash` (string): bcrypt hash - `role` (enum): USER or ADMIN **Relationships**: - Has one Artist - Has one Label - Has many Playlists - Has many Shares
🔧 Technical Details - User Schema ```prisma model User { id String @id @default(uuid()) email String @unique username String @unique displayName String? passwordHash String role Role @default(USER) avatarUrl String? bio String? websiteUrl String? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt artist Artist? label Label? playlists Playlist[] shares Share[] } enum Role { USER ADMIN } ```
--- ### Artist Extended profile for musicians who upload content. **Key Fields**: - `id` (UUID): Primary key - `userId` (UUID): Foreign key to User (one-to-one) - `name` (string): Artist name - `slug` (string): URL-friendly identifier - `verified` (boolean): Official verification badge - `labelId` (UUID): Optional foreign key to Label **Relationships**: - Belongs to User - Belongs to Label (optional) - Has many Songs - Has many Albums
🔧 Technical Details - Artist Schema ```prisma model Artist { id String @id @default(uuid()) userId String @unique name String slug String @unique bio String? avatarUrl String? verified Boolean @default(false) websiteUrl String? labelId String? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt user User @relation(fields: [userId], references: [id]) label Label? @relation(fields: [labelId], references: [id]) songs Song[] albums Album[] @@index([slug]) @@index([labelId]) } ``` **Slug Generation**: Lowercase, hyphens for spaces, alphanumeric only
--- ### Label Organization that manages multiple artists. **Key Fields**: - `id` (UUID): Primary key - `userId` (UUID): Foreign key to User (owner) - `name` (string): Label name - `slug` (string): URL-friendly identifier - `description` (string): About the label **Relationships**: - Belongs to User (owner) - Has many Artists - Has many LabelInvitations --- ### Genre Music category tags for organization and discovery. **Key Fields**: - `id` (UUID): Primary key - `name` (string): Genre name - `slug` (string): URL-friendly identifier - `description` (string): Genre description - `color` (string): Hex color code for UI **Relationships**: - Has many SongGenre (junction) **Example Genres**: Rock, Jazz, Electronic, Hip-Hop, Classical, Pop --- ### Album Collection of songs released together. **Key Fields**: - `id` (UUID): Primary key - `artistId` (UUID): Foreign key to Artist - `title` (string): Album title - `releaseDate` (DateTime): Release date - `albumType` (enum): ALBUM, EP, or SINGLE - `coverImageUrl` (string): Album artwork URL **Relationships**: - Belongs to Artist - Has many Songs
🔧 Technical Details - Album Schema ```prisma model Album { id String @id @default(uuid()) artistId String title String releaseDate DateTime albumType AlbumType @default(ALBUM) coverImageUrl String? description String? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt artist Artist @relation(fields: [artistId], references: [id]) songs Song[] @@index([artistId]) @@index([releaseDate]) } enum AlbumType { ALBUM EP SINGLE } ```
--- ### Song Individual audio track with metadata and analytics. **Key Fields**: - `id` (UUID): Primary key - `artistId` (UUID): Foreign key to Artist - `albumId` (UUID): Optional foreign key to Album - `title` (string): Song title - `audioUrl` (string): URL to audio file - `duration` (number): Length in seconds - `playCount` (number): Total plays across platform - `isPublic` (boolean): Visibility control **Relationships**: - Belongs to Artist - Belongs to Album (optional) - Has many SongGenre (junction) - Has many PlaylistSong (junction)
🔧 Technical Details - Song Schema ```prisma model Song { id String @id @default(uuid()) artistId String albumId String? title String audioUrl String coverImageUrl String? duration Int // seconds playCount Int @default(0) isPublic Boolean @default(true) description String? lyrics String? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt artist Artist @relation(fields: [artistId], references: [id]) album Album? @relation(fields: [albumId], references: [id]) genres SongGenre[] playlists PlaylistSong[] @@index([artistId]) @@index([albumId]) @@index([playCount]) @@index([createdAt]) } ``` **Indexes**: Optimized for queries on artist, album, play count (trending), and creation date (new releases)
--- ### Playlist User-created collection of songs. **Key Fields**: - `id` (UUID): Primary key - `userId` (UUID): Foreign key to User (owner) - `title` (string): Playlist name - `description` (string): Optional description - `isPublic` (boolean): Privacy control - `coverImageUrl` (string): Playlist artwork URL **Relationships**: - Belongs to User - Has many PlaylistSong (junction)
🔧 Technical Details - Playlist Schema ```prisma model Playlist { id String @id @default(uuid()) userId String title String description String? isPublic Boolean @default(false) coverImageUrl String? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt user User @relation(fields: [userId], references: [id]) songs PlaylistSong[] @@index([userId]) } model PlaylistSong { id String @id @default(uuid()) playlistId String songId String position Int // For ordering addedAt DateTime @default(now()) playlist Playlist @relation(fields: [playlistId], references: [id]) song Song @relation(fields: [songId], references: [id]) @@unique([playlistId, songId]) @@index([playlistId, position]) } ``` **Position**: 0-based integer for stable song ordering within playlist
--- ### LabelInvitation Invitation workflow for labels recruiting artists. **Key Fields**: - `id` (UUID): Primary key - `labelId` (UUID): Foreign key to Label - `artistId` (UUID): Foreign key to Artist - `status` (enum): PENDING, ACCEPTED, DECLINED, EXPIRED - `expiresAt` (DateTime): Invitation expiration **Relationships**: - Belongs to Label - Belongs to Artist
🔧 Technical Details - Invitation Lifecycle **States**: 1. **PENDING**: Initial state after creation 2. **ACCEPTED**: Artist accepts → artistId gets labelId assigned 3. **DECLINED**: Artist rejects invitation 4. **EXPIRED**: expiresAt passes without action **Expiration**: Default 7 days from creation
--- ### Share Shareable content links with analytics. **Key Fields**: - `id` (UUID): Primary key - `type` (enum): SONG, PLAYLIST, or ALBUM - `targetId` (UUID): ID of shared content - `token` (string): Unique 10-character code - `clickCount` (number): Tracking metric - `userId` (UUID): Optional creator **Relationships**: - Belongs to User (optional)
🔧 Technical Details - Share Schema ```prisma model Share { id String @id @default(uuid()) type ShareType targetId String token String @unique userId String? clickCount Int @default(0) createdAt DateTime @default(now()) user User? @relation(fields: [userId], references: [id]) @@index([token]) @@index([targetId]) } enum ShareType { SONG PLAYLIST ALBUM } ``` **Token Generation**: `nanoid(10)` - URL-safe, lowercase + numbers
--- ## Entity Relationship Diagram ``` ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ USER │──────<│ ARTIST │──────<│ SONG │ │ │ 1:1 │ │ 1:N │ │ │ - id │ │ - id │ │ - id │ │ - email │ │ - userId │ │ - artistId │ │ - username │ │ - name │ │ - title │ │ - password │ │ - slug │ │ - audioUrl │ │ - role │ │ - verified │ │ - playCount │ └──────┬───────┘ └──────┬───────┘ └──────┬───────┘ │ │ │ │ 1:1 │ N:1 │ N:M │ │ │ ▼ ▼ ▼ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ LABEL │ │ ALBUM │ │ SONGGENRE │ │ │ │ │ │ (junction) │ │ - id │ │ - id │ │ │ │ - userId │ │ - artistId │ │ - songId │ │ - name │──────<│ - title │ │ - genreId │ │ - slug │ 1:N │ - releaseDate│ └──────┬───────┘ └──────┬───────┘ └──────┬───────┘ │ N:1 │ │ │ │ 1:N │ 1:N ▼ │ │ ┌──────────────┐ ▼ │ │ GENRE │ ┌──────────────┐ │ │ │ │ LABELINVITE │ │ │ - id │ │ │ │ │ - name │ │ - labelId │ │ │ - slug │ │ - artistId │ │ │ - color │ │ - status │ │ └──────────────┘ └──────────────┘ │ │ ┌──────────────────────┘ │ ▼ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ PLAYLIST │──────<│ PLAYLISTSONG │>──────│ SONG │ │ │ 1:N │ (junction) │ N:1 │ (see above) │ │ - id │ │ │ │ │ │ - userId │ │ - playlistId │ └──────────────┘ │ - title │ │ - songId │ │ - isPublic │ │ - position │ └──────────────┘ └──────────────┘ ┌──────────────┐ │ SHARE │ │ │ │ - id │ │ - type │──── References SONG | PLAYLIST | ALBUM │ - targetId │ │ - token │ │ - clickCount │ └──────────────┘ ``` --- ## Components The UI is built from 20 reusable React components organized by function. ### Audio Components #### AudioPlayer Fixed bottom player that follows across all pages. **Features**: - Song info display (title, artist, cover) - Play/pause, next/previous buttons - Progress bar with seek functionality - Volume slider and mute toggle - Current time / total duration display **Location**: `components/AudioPlayer.tsx`
🔧 Technical Details - AudioPlayer Implementation **State Management**: ```typescript interface PlayerState { currentSong: Song | null; isPlaying: boolean; currentTime: number; duration: number; volume: number; isMuted: boolean; queue: Song[]; queueIndex: number; repeatMode: "off" | "one" | "all"; isShuffled: boolean; } ``` **Audio Element**: HTML5 `
--- #### PlayerControls Reusable control buttons for audio playback. **Buttons**: - Play/pause toggle - Previous track - Next track - Shuffle toggle - Repeat cycle (off → all → one) **Location**: `components/PlayerControls.tsx` --- #### WaveformDisplay Visual audio waveform with interactive seeking. **Features**: - Canvas-based rendering - Progress indicator overlay - Click-to-seek functionality - Responsive width **Location**: `components/WaveformDisplay.tsx`
🔧 Technical Details - Waveform Rendering **Canvas Drawing**: 1. Parse audio amplitude data (Web Audio API) 2. Draw vertical bars for each sample 3. Color code: played (blue), unplayed (gray) 4. Update on time change **Performance**: Debounced redraw to prevent excessive rendering
--- ### Card Components Display content previews in grid layouts. #### SongCard Shows song thumbnail, title, artist, duration, play count. #### AlbumCard Shows album art, title, artist, release year, track count. #### ArtistCard Shows circular avatar, artist name, verified badge. #### PlaylistCard Shows playlist cover, title, song count, privacy indicator. #### LabelCard Shows label logo, name, artist count. #### GenreBadge Clickable colored badge with genre name. **All card locations**: `components/*.tsx` --- ### Form Components #### AuthForm Unified form for login, register, password reset modes. **Fields**: - Email (all modes) - Password (login, register) - Username (register only) - Display name (register, optional) **Location**: `components/AuthForm.tsx` --- #### UploadForm Multi-field form for song uploads. **Fields**: - Title (required) - Audio file URL (required) - Cover image URL (optional) - Duration in seconds (required) - Album selection (dropdown) - Genre tags (multi-select) - Description (textarea) - Lyrics (textarea) - Public/private toggle **Location**: `components/UploadForm.tsx` --- #### ProfileForm Edit user profile data. **Fields**: - Display name - Email (read-only) - Bio (textarea) - Website URL - Avatar URL **Location**: `components/ProfileForm.tsx` --- #### CreatePlaylistModal Modal dialog for new playlist creation. **Fields**: - Title (required) - Description (optional) - Public/private toggle - Cover image URL (optional) **Location**: `components/CreatePlaylistModal.tsx` --- ### Navigation Components #### Header Fixed top navigation bar. **Elements**: - Logo (link to home) - Nav links (Discover, Genres, Artists, Labels) - Search bar - User menu (if logged in) - Login button (if logged out) - Mobile menu toggle **Location**: `components/Header.tsx` --- #### NavLink Navigation link with active state. **Features**: - Highlights current page - Uses Next.js router for path matching **Location**: `components/NavLink.tsx` --- #### UserMenu Dropdown menu for authenticated users. **Links**: - Profile - Upload Song - My Playlists - Logout **Location**: `components/UserMenu.tsx` --- #### SearchBar Real-time search input with suggestions. **Features**: - Debounced input (300ms) - Dropdown with results preview - Loading indicator - Keyboard navigation (arrow keys, enter) **Location**: `components/SearchBar.tsx`
🔧 Technical Details - Search Debouncing ```typescript const [query, setQuery] = useState(""); const [results, setResults] = useState([]); // Debounce search API calls useEffect(() => { const timer = setTimeout(async () => { if (query.length >= 2) { const data = await fetch(`/api/search?q=${query}`); setResults(data); } }, 300); return () => clearTimeout(timer); }, [query]); ```
--- ### Sharing Components #### ShareButton Button that generates shareable links. **Actions**: 1. Click button 2. Generate share token (POST to `/api/share/*`) 3. Open ShareModal with link **Location**: `components/ShareButton.tsx` --- #### ShareModal Modal displaying shareable link. **Features**: - Copy-to-clipboard button - QR code (optional) - Social media share buttons - Click count display **Location**: `components/ShareModal.tsx` --- ### Display Components #### TrackList Scrollable list of songs with metadata. **Columns**: - Position number - Cover image - Title - Artist name - Duration **Actions**: - Click to play - Right-click context menu (add to playlist, share) **Location**: `components/TrackList.tsx` --- ## Glossary **API Endpoint**: A specific URL where a program can request data or send commands. Like an address where your app talks to the server. **Album**: A collection of songs released together, like a CD or digital release. **Artist**: A musician or band that creates and uploads music to the platform. **Authentication**: The process of verifying who you are (usually with email and password). **bcryptjs**: A library that scrambles passwords so they can't be read if the database is stolen. **Cover Image**: The picture displayed for a song, album, or playlist. **Duration**: How long a song is in minutes and seconds. **EP**: Extended Play - a short music release with 3-7 tracks (less than an album, more than a single). **Genre**: A category of music like Rock, Jazz, Hip-Hop, or Electronic. **JWT (JSON Web Token)**: A secure way to remember that you're logged in without storing passwords. Like a temporary pass that expires after 7 days. **Label**: A music organization that manages multiple artists (like a record company). **ORM (Object-Relational Mapping)**: A tool that lets programmers work with databases using normal code instead of SQL queries. Prisma is the ORM used here. **Play Count**: The total number of times a song has been played by all users. **Playlist**: A custom collection of songs you create (like making a mixtape). **Prisma**: The database tool used to manage data in this project. It ensures type safety and generates database queries automatically. **Public/Private**: Public content is visible to everyone; private content is only visible to you. **REST API**: A standard way for programs to communicate over the internet using HTTP requests (GET, POST, PUT, DELETE). **Share Token**: A unique short code (like `aBc123XyZ`) used to create shareable links. **Slug**: A URL-friendly version of a name. For example, "The Beatles" becomes "the-beatles" in URLs. **SQLite**: A lightweight database stored in a single file. Good for development and small-to-medium projects. **TypeScript**: A version of JavaScript that checks for errors before the code runs, making development safer. **UUID (Universally Unique Identifier)**: A long random ID like `550e8400-e29b-41d4-a716-446655440000` that ensures every record is unique. **Verified Badge**: A checkmark showing an artist is officially recognized (like Twitter's blue checkmark). **Waveform**: A visual representation of audio that shows the loudness of a song over time. Looks like a series of vertical bars. --- ## Project Statistics | Metric | Count | |--------|-------| | Total Files | 107 | | TypeScript Files | 107 | | API Endpoints | 40 | | Database Models | 10 | | Pages | 13 | | UI Components | 20 | | Type Definition Files | 4 | | Utility Library Files | 3 | --- ## Development Workflow This project uses the **Guardrail Workflow System** to enforce a structured development process. ### Workflow Phases 1. **Design Phase**: Plan changes and update manifest 2. **Approval Gate**: Review and approve design 3. **Implementation Phase**: Write code following approved design 4. **Review Phase**: Quality checks and validation 5. **Approval Gate**: Final approval before completion ### Quick Commands ```bash # Start a new feature workflow /workflow:spawn add user notifications # Check current workflow status /workflow:status # Approve current phase /workflow:approve # Generate documentation /eureka:index ``` See `CLAUDE.md` for full workflow documentation. --- ## Next Steps ### For New Users 1. Explore the codebase structure in the sections above 2. Run the development server and test the UI 3. Read API endpoint documentation for integration 4. Review data models to understand relationships ### For Contributors 1. Read the workflow documentation in `CLAUDE.md` 2. Use `/workflow:spawn` to start new features 3. Follow the design-approve-implement cycle 4. Run `/workflow:review` before submitting changes ### For Operators 1. Review deployment requirements 2. Configure environment variables (JWT secret, database URL) 3. Set up file storage for audio uploads 4. Consider PostgreSQL migration for production scale --- **Generated by Eureka Documentation System** **Last Updated**: 2025-12-18