232 lines
6.0 KiB
Plaintext
232 lines
6.0 KiB
Plaintext
// Prisma schema for Sonic Cloud - Music Platform
|
|
// Models: User, Artist, Label, Genre, Album, Song, SongGenre, Playlist, PlaylistSong
|
|
|
|
generator client {
|
|
provider = "prisma-client-js"
|
|
}
|
|
|
|
datasource db {
|
|
provider = "sqlite"
|
|
url = env("DATABASE_URL")
|
|
}
|
|
|
|
// User model - base authentication and profile
|
|
model User {
|
|
id String @id @default(uuid())
|
|
email String @unique
|
|
passwordHash String
|
|
username String @unique
|
|
displayName String?
|
|
avatarUrl String?
|
|
bio String?
|
|
role String @default("user") // user, artist, label, admin
|
|
resetToken String?
|
|
resetExpires DateTime?
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
// Relations
|
|
artist Artist?
|
|
label Label?
|
|
playlists Playlist[]
|
|
shares Share[]
|
|
|
|
@@map("users")
|
|
}
|
|
|
|
// Artist model - for musicians who upload music
|
|
model Artist {
|
|
id String @id @default(uuid())
|
|
userId String @unique
|
|
name String
|
|
slug String @unique
|
|
bio String?
|
|
avatarUrl String?
|
|
bannerUrl String?
|
|
website String?
|
|
twitter String?
|
|
instagram String?
|
|
spotify String?
|
|
verified Boolean @default(false)
|
|
labelId String?
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
// Relations
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
label Label? @relation(fields: [labelId], references: [id])
|
|
songs Song[]
|
|
albums Album[]
|
|
invitations LabelInvitation[]
|
|
|
|
@@map("artists")
|
|
}
|
|
|
|
// Label model - record labels that manage artists
|
|
model Label {
|
|
id String @id @default(uuid())
|
|
userId String @unique
|
|
name String
|
|
slug String @unique
|
|
description String?
|
|
logoUrl String?
|
|
website String?
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
// Relations
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
artists Artist[]
|
|
invitations LabelInvitation[]
|
|
|
|
@@map("labels")
|
|
}
|
|
|
|
// Genre model - music genres for categorization
|
|
model Genre {
|
|
id String @id @default(uuid())
|
|
name String @unique
|
|
slug String @unique
|
|
description String?
|
|
color String? // hex color for UI
|
|
createdAt DateTime @default(now())
|
|
|
|
// Relations
|
|
songs SongGenre[]
|
|
|
|
@@map("genres")
|
|
}
|
|
|
|
// Album model - collection of songs
|
|
model Album {
|
|
id String @id @default(uuid())
|
|
artistId String
|
|
title String
|
|
slug String
|
|
description String?
|
|
coverUrl String?
|
|
releaseDate DateTime?
|
|
albumType String @default("album") // album, single, ep
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
// Relations
|
|
artist Artist @relation(fields: [artistId], references: [id], onDelete: Cascade)
|
|
songs Song[]
|
|
|
|
@@unique([artistId, slug])
|
|
@@map("albums")
|
|
}
|
|
|
|
// Song model - individual music tracks
|
|
model Song {
|
|
id String @id @default(uuid())
|
|
artistId String
|
|
albumId String?
|
|
title String
|
|
slug String
|
|
description String?
|
|
audioUrl String
|
|
coverUrl String?
|
|
duration Int // duration in seconds
|
|
waveformUrl String? // waveform visualization data
|
|
playCount Int @default(0)
|
|
isPublic Boolean @default(true)
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
// Relations
|
|
artist Artist @relation(fields: [artistId], references: [id], onDelete: Cascade)
|
|
album Album? @relation(fields: [albumId], references: [id], onDelete: SetNull)
|
|
genres SongGenre[]
|
|
playlists PlaylistSong[]
|
|
|
|
@@unique([artistId, slug])
|
|
@@map("songs")
|
|
}
|
|
|
|
// SongGenre model - many-to-many relation between songs and genres
|
|
model SongGenre {
|
|
songId String
|
|
genreId String
|
|
|
|
song Song @relation(fields: [songId], references: [id], onDelete: Cascade)
|
|
genre Genre @relation(fields: [genreId], references: [id], onDelete: Cascade)
|
|
|
|
@@id([songId, genreId])
|
|
@@map("song_genres")
|
|
}
|
|
|
|
// Playlist model - user-created playlists
|
|
model Playlist {
|
|
id String @id @default(uuid())
|
|
userId String
|
|
title String
|
|
slug String
|
|
description String?
|
|
coverUrl String?
|
|
isPublic Boolean @default(true)
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
// Relations
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
songs PlaylistSong[]
|
|
|
|
@@unique([userId, slug])
|
|
@@map("playlists")
|
|
}
|
|
|
|
// PlaylistSong model - many-to-many relation with ordering
|
|
model PlaylistSong {
|
|
playlistId String
|
|
songId String
|
|
position Int
|
|
addedAt DateTime @default(now())
|
|
|
|
playlist Playlist @relation(fields: [playlistId], references: [id], onDelete: Cascade)
|
|
song Song @relation(fields: [songId], references: [id], onDelete: Cascade)
|
|
|
|
@@id([playlistId, songId])
|
|
@@map("playlist_songs")
|
|
}
|
|
|
|
// Label invitation model - invitations from labels to artists
|
|
model LabelInvitation {
|
|
id String @id @default(uuid())
|
|
labelId String
|
|
artistId String
|
|
status String @default("pending") // pending, accepted, declined, expired
|
|
message String?
|
|
expiresAt DateTime
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
// Relations
|
|
label Label @relation(fields: [labelId], references: [id], onDelete: Cascade)
|
|
artist Artist @relation(fields: [artistId], references: [id], onDelete: Cascade)
|
|
|
|
@@unique([labelId, artistId])
|
|
@@index([artistId, status])
|
|
@@map("label_invitations")
|
|
}
|
|
|
|
// Share model - tracks shared content links
|
|
model Share {
|
|
id String @id @default(cuid())
|
|
type String // SONG, PLAYLIST, or ALBUM
|
|
targetId String
|
|
token String @unique
|
|
userId String?
|
|
platform String?
|
|
clickCount Int @default(0)
|
|
createdAt DateTime @default(now())
|
|
|
|
// Relations
|
|
user User? @relation(fields: [userId], references: [id], onDelete: SetNull)
|
|
|
|
@@index([token])
|
|
@@index([targetId, type])
|
|
@@map("shares")
|
|
}
|