project-standalo-sonic-cloud/docs/PROJECT_DOCUMENTATION.md

40 KiB

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

# Install dependencies
npm install

# Set up database
npx prisma generate
npx prisma db push

# Start development server
npm run dev

Open 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
POST /api/songs/upload
Headers: { Authorization: "Bearer <jwt_token>" }
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
// 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
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
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
// 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
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
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:

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:

POST /api/auth/login
Body: {
  email: string,
  password: string
}

Response: {
  user: { id, email, username, role },
  token: string
}

JWT Payload:

{
  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 <token> 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:

POST /api/artists
Body: {
  name: string,
  bio?: string,
  avatarUrl?: string,
  websiteUrl?: string
}

// Automatically generates slug from name
// Associates with authenticated userId

Get Artist:

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
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
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
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
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
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
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
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:

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 <audio> element controlled by React state

Time Updates: ontimeupdate event updates progress bar every ~250ms


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


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


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
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

# 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