Index: finkwave/src/main/java/com/ukim/finki/develop/finkwave/controller/SongController.java
===================================================================
--- finkwave/src/main/java/com/ukim/finki/develop/finkwave/controller/SongController.java	(revision dc30259a457c1232ee6ee1f6096c9fa50172e058)
+++ finkwave/src/main/java/com/ukim/finki/develop/finkwave/controller/SongController.java	(revision 8a47b30f7be0c80847e0bb6d30060d214d1bd85d)
@@ -3,14 +3,13 @@
 import com.ukim.finki.develop.finkwave.model.dto.BasicSongDto;
 import com.ukim.finki.develop.finkwave.model.dto.MusicalEntityDto;
+import com.ukim.finki.develop.finkwave.model.dto.SongDetailsDto;
 import com.ukim.finki.develop.finkwave.repository.SongRepository;
 import com.ukim.finki.develop.finkwave.service.AuthService;
 import com.ukim.finki.develop.finkwave.service.SongService;
 import lombok.AllArgsConstructor;
+import org.springframework.data.repository.query.Param;
 import org.springframework.http.HttpEntity;
 import org.springframework.http.ResponseEntity;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestParam;
-import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.bind.annotation.*;
 
 import java.util.List;
@@ -37,3 +36,8 @@
         return ResponseEntity.ok(songService.getRecentlyListened());
     }
+
+    @GetMapping("/{songId}/details")
+    public HttpEntity<SongDetailsDto> getSongById(@PathVariable Long songId){
+        return ResponseEntity.ok(songService.getSongDetails(songId));
+    }
 }
Index: finkwave/src/main/java/com/ukim/finki/develop/finkwave/model/dto/ArtistContributionSummaryDto.java
===================================================================
--- finkwave/src/main/java/com/ukim/finki/develop/finkwave/model/dto/ArtistContributionSummaryDto.java	(revision 8a47b30f7be0c80847e0bb6d30060d214d1bd85d)
+++ finkwave/src/main/java/com/ukim/finki/develop/finkwave/model/dto/ArtistContributionSummaryDto.java	(revision 8a47b30f7be0c80847e0bb6d30060d214d1bd85d)
@@ -0,0 +1,12 @@
+package com.ukim.finki.develop.finkwave.model.dto;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+// this dto is useful when we already have all the necessary info for the song and just need the contribution info
+@Getter
+@AllArgsConstructor
+public class ArtistContributionSummaryDto {
+    private String artistName;
+    private String role;
+}
Index: finkwave/src/main/java/com/ukim/finki/develop/finkwave/model/dto/ArtistDto.java
===================================================================
--- finkwave/src/main/java/com/ukim/finki/develop/finkwave/model/dto/ArtistDto.java	(revision dc30259a457c1232ee6ee1f6096c9fa50172e058)
+++ finkwave/src/main/java/com/ukim/finki/develop/finkwave/model/dto/ArtistDto.java	(revision 8a47b30f7be0c80847e0bb6d30060d214d1bd85d)
@@ -9,7 +9,4 @@
 @Setter
 public class ArtistDto extends NonAdminUserDto {
-
-
     private List<ArtistContributionDto> contributions;
-
 }
Index: finkwave/src/main/java/com/ukim/finki/develop/finkwave/model/dto/MusicalEntityDto.java
===================================================================
--- finkwave/src/main/java/com/ukim/finki/develop/finkwave/model/dto/MusicalEntityDto.java	(revision dc30259a457c1232ee6ee1f6096c9fa50172e058)
+++ finkwave/src/main/java/com/ukim/finki/develop/finkwave/model/dto/MusicalEntityDto.java	(revision 8a47b30f7be0c80847e0bb6d30060d214d1bd85d)
@@ -4,4 +4,5 @@
 import lombok.AllArgsConstructor;
 import lombok.Getter;
+import lombok.NoArgsConstructor;
 import lombok.Setter;
 
@@ -9,4 +10,5 @@
 @Getter
 @Setter
+@NoArgsConstructor
 public class MusicalEntityDto {
     private Long id;
Index: finkwave/src/main/java/com/ukim/finki/develop/finkwave/model/dto/ReviewDto.java
===================================================================
--- finkwave/src/main/java/com/ukim/finki/develop/finkwave/model/dto/ReviewDto.java	(revision 8a47b30f7be0c80847e0bb6d30060d214d1bd85d)
+++ finkwave/src/main/java/com/ukim/finki/develop/finkwave/model/dto/ReviewDto.java	(revision 8a47b30f7be0c80847e0bb6d30060d214d1bd85d)
@@ -0,0 +1,14 @@
+package com.ukim.finki.develop.finkwave.model.dto;
+
+import com.ukim.finki.develop.finkwave.model.ReviewId;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+@Getter
+@AllArgsConstructor
+public class ReviewDto {
+    private ReviewId id;
+    private String author;
+    private Integer grade;
+    private String comment;
+}
Index: finkwave/src/main/java/com/ukim/finki/develop/finkwave/model/dto/SongDetailsDto.java
===================================================================
--- finkwave/src/main/java/com/ukim/finki/develop/finkwave/model/dto/SongDetailsDto.java	(revision 8a47b30f7be0c80847e0bb6d30060d214d1bd85d)
+++ finkwave/src/main/java/com/ukim/finki/develop/finkwave/model/dto/SongDetailsDto.java	(revision 8a47b30f7be0c80847e0bb6d30060d214d1bd85d)
@@ -0,0 +1,34 @@
+package com.ukim.finki.develop.finkwave.model.dto;
+
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+import java.util.List;
+
+@Getter
+@Setter
+@NoArgsConstructor
+public class SongDetailsDto extends SongDto{
+    private List<ArtistContributionSummaryDto> contributions;
+    private List<ReviewDto> reviews;
+
+    public SongDetailsDto(Long id, String title, String genre, String type, String releasedBy, String cover, Boolean isLikedByCurrentUser, String album, String link, List<ArtistContributionSummaryDto> contributions, List<ReviewDto> reviews) {
+        super(id, title, genre, type, releasedBy, cover, isLikedByCurrentUser, album, link);
+        this.contributions = contributions;
+        this.reviews = reviews;
+    }
+
+    public SongDetailsDto(Long id, String title, String genre, String type, String releasedBy, Boolean isLikedByCurrentUser, String link, List<ArtistContributionSummaryDto> contributions, List<ReviewDto> reviews) {
+        super(id, title, genre, type, releasedBy, isLikedByCurrentUser, link);
+        this.contributions = contributions;
+        this.reviews = reviews;
+    }
+
+    public SongDetailsDto(Long id, String title, String genre, String type, String releasedBy, String cover, Boolean isLikedByCurrentUser, String link, List<ArtistContributionSummaryDto> contributions, List<ReviewDto> reviews) {
+        super(id, title, genre, type, releasedBy, cover, isLikedByCurrentUser, link);
+        this.contributions = contributions;
+        this.reviews = reviews;
+    }
+
+}
Index: finkwave/src/main/java/com/ukim/finki/develop/finkwave/model/dto/SongDto.java
===================================================================
--- finkwave/src/main/java/com/ukim/finki/develop/finkwave/model/dto/SongDto.java	(revision 8a47b30f7be0c80847e0bb6d30060d214d1bd85d)
+++ finkwave/src/main/java/com/ukim/finki/develop/finkwave/model/dto/SongDto.java	(revision 8a47b30f7be0c80847e0bb6d30060d214d1bd85d)
@@ -0,0 +1,30 @@
+package com.ukim.finki.develop.finkwave.model.dto;
+
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+@Getter
+@Setter
+@NoArgsConstructor
+public class SongDto extends MusicalEntityDto{
+    private String link;
+
+    // todo: clean up constructors
+
+    public SongDto(Long id, String title, String genre, String type, String releasedBy, String cover, Boolean isLikedByCurrentUser, String album, String link) {
+        super(id, title, genre, type, releasedBy, cover, isLikedByCurrentUser, album);
+        this.link = link;
+    }
+
+    public SongDto(Long id, String title, String genre, String type, String releasedBy, Boolean isLikedByCurrentUser, String link) {
+        super(id, title, genre, type, releasedBy, isLikedByCurrentUser);
+        this.link = link;
+    }
+
+    public SongDto(Long id, String title, String genre, String type, String releasedBy, String cover, Boolean isLikedByCurrentUser, String link) {
+        super(id, title, genre, type, releasedBy, cover, isLikedByCurrentUser);
+        this.link = link;
+    }
+
+}
Index: finkwave/src/main/java/com/ukim/finki/develop/finkwave/repository/ArtistContributionRepository.java
===================================================================
--- finkwave/src/main/java/com/ukim/finki/develop/finkwave/repository/ArtistContributionRepository.java	(revision dc30259a457c1232ee6ee1f6096c9fa50172e058)
+++ finkwave/src/main/java/com/ukim/finki/develop/finkwave/repository/ArtistContributionRepository.java	(revision 8a47b30f7be0c80847e0bb6d30060d214d1bd85d)
@@ -2,4 +2,5 @@
 
 import com.ukim.finki.develop.finkwave.model.dto.ArtistContributionDto;
+import com.ukim.finki.develop.finkwave.model.dto.ArtistContributionSummaryDto;
 import org.springframework.data.jpa.repository.JpaRepository;
 import org.springframework.data.jpa.repository.Query;
@@ -28,3 +29,13 @@
         """)
     List<ArtistContributionDto>findContributionsByArtistId(@Param("currentUserId")Long currentUserId,@Param("artistId")Long artistId);
+
+
+    @Query("""
+    SELECT NEW com.ukim.finki.develop.finkwave.model.dto.ArtistContributionSummaryDto(
+    ac.artist.nonAdminUser.user.fullName, ac.role
+    )
+    FROM ArtistContribution ac
+    WHERE ac.id.musicalEntityId = :songId
+    """)
+    List<ArtistContributionSummaryDto> findContributionsBySongId(@Param("songId")Long songId);
 }
Index: finkwave/src/main/java/com/ukim/finki/develop/finkwave/repository/ReviewRepository.java
===================================================================
--- finkwave/src/main/java/com/ukim/finki/develop/finkwave/repository/ReviewRepository.java	(revision dc30259a457c1232ee6ee1f6096c9fa50172e058)
+++ finkwave/src/main/java/com/ukim/finki/develop/finkwave/repository/ReviewRepository.java	(revision 8a47b30f7be0c80847e0bb6d30060d214d1bd85d)
@@ -1,5 +1,8 @@
 package com.ukim.finki.develop.finkwave.repository;
 
+import com.ukim.finki.develop.finkwave.model.dto.ReviewDto;
 import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.data.repository.query.Param;
 import org.springframework.stereotype.Repository;
 
@@ -7,5 +10,18 @@
 import com.ukim.finki.develop.finkwave.model.ReviewId;
 
+import java.util.List;
+
 @Repository
 public interface ReviewRepository extends JpaRepository<Review, ReviewId> {
+    @Query("""
+        SELECT NEW com.ukim.finki.develop.finkwave.model.dto.ReviewDto(
+        r.id,
+        r.listener.nonAdminUser.user.fullName,
+        r.grade,
+        r.comment
+        )
+        FROM Review r
+        WHERE r.id.musicalEntityId = :songId
+    """)
+    List<ReviewDto> getReviewsForSongId(@Param("songId") Long songId);
 }
Index: finkwave/src/main/java/com/ukim/finki/develop/finkwave/repository/SongRepository.java
===================================================================
--- finkwave/src/main/java/com/ukim/finki/develop/finkwave/repository/SongRepository.java	(revision dc30259a457c1232ee6ee1f6096c9fa50172e058)
+++ finkwave/src/main/java/com/ukim/finki/develop/finkwave/repository/SongRepository.java	(revision 8a47b30f7be0c80847e0bb6d30060d214d1bd85d)
@@ -3,7 +3,9 @@
 import com.ukim.finki.develop.finkwave.model.dto.BasicSongDto;
 import com.ukim.finki.develop.finkwave.model.dto.MusicalEntityDto;
+import com.ukim.finki.develop.finkwave.model.dto.SongDto;
 import org.springframework.data.jpa.repository.JpaRepository;
 import org.springframework.data.jpa.repository.Query;
 import org.springframework.data.repository.query.Param;
+import org.springframework.security.core.parameters.P;
 import org.springframework.stereotype.Repository;
 
@@ -96,3 +98,30 @@
     """, nativeQuery = true)
     List<BasicSongDto> getRecentlyListened(@Param("userId")Long userId);
+
+    @Query(value = """
+        SELECT NEW com.ukim.finki.develop.finkwave.model.dto.SongDto(
+            s.id,
+            me.title,
+            me.genre,
+            'SONG',
+            u.fullName,
+            me.cover,
+            (EXISTS (
+                SELECT 1 FROM Like l
+                WHERE l.musicalEntity.id = s.id
+                  AND l.listener.id = :userId
+            )),
+            albumMe.title,
+            s.link
+        )
+        FROM Song s
+        JOIN s.musicalEntities me
+        JOIN me.releasedBy a
+        JOIN a.nonAdminUser nau
+        JOIN nau.user u
+        LEFT JOIN s.album album
+        LEFT JOIN album.musicalEntities albumMe
+        WHERE s.id = :songId
+    """)
+    SongDto getSongById(@Param("songId") Long songId, @Param("userId") Long userId);
 }
Index: finkwave/src/main/java/com/ukim/finki/develop/finkwave/service/ArtistContributionService.java
===================================================================
--- finkwave/src/main/java/com/ukim/finki/develop/finkwave/service/ArtistContributionService.java	(revision 8a47b30f7be0c80847e0bb6d30060d214d1bd85d)
+++ finkwave/src/main/java/com/ukim/finki/develop/finkwave/service/ArtistContributionService.java	(revision 8a47b30f7be0c80847e0bb6d30060d214d1bd85d)
@@ -0,0 +1,18 @@
+package com.ukim.finki.develop.finkwave.service;
+
+import com.ukim.finki.develop.finkwave.model.dto.ArtistContributionSummaryDto;
+import com.ukim.finki.develop.finkwave.repository.ArtistContributionRepository;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+@Service
+@RequiredArgsConstructor
+public class ArtistContributionService {
+    private final ArtistContributionRepository artistContributionRepository;
+
+    public List<ArtistContributionSummaryDto> getContributionsBySongId(Long songId){
+        return artistContributionRepository.findContributionsBySongId(songId);
+    }
+}
Index: finkwave/src/main/java/com/ukim/finki/develop/finkwave/service/ReviewService.java
===================================================================
--- finkwave/src/main/java/com/ukim/finki/develop/finkwave/service/ReviewService.java	(revision 8a47b30f7be0c80847e0bb6d30060d214d1bd85d)
+++ finkwave/src/main/java/com/ukim/finki/develop/finkwave/service/ReviewService.java	(revision 8a47b30f7be0c80847e0bb6d30060d214d1bd85d)
@@ -0,0 +1,18 @@
+package com.ukim.finki.develop.finkwave.service;
+
+import com.ukim.finki.develop.finkwave.model.dto.ReviewDto;
+import com.ukim.finki.develop.finkwave.repository.ReviewRepository;
+import lombok.AllArgsConstructor;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+@Service
+@AllArgsConstructor
+public class ReviewService {
+    private final ReviewRepository reviewRepository;
+
+    public List<ReviewDto> getReviewsForSongId(Long songId){
+        return reviewRepository.getReviewsForSongId(songId);
+    }
+}
Index: finkwave/src/main/java/com/ukim/finki/develop/finkwave/service/SongService.java
===================================================================
--- finkwave/src/main/java/com/ukim/finki/develop/finkwave/service/SongService.java	(revision dc30259a457c1232ee6ee1f6096c9fa50172e058)
+++ finkwave/src/main/java/com/ukim/finki/develop/finkwave/service/SongService.java	(revision 8a47b30f7be0c80847e0bb6d30060d214d1bd85d)
@@ -1,7 +1,7 @@
 package com.ukim.finki.develop.finkwave.service;
 
-import com.ukim.finki.develop.finkwave.model.dto.BasicSongDto;
-import com.ukim.finki.develop.finkwave.model.dto.MusicalEntityDto;
+import com.ukim.finki.develop.finkwave.model.dto.*;
 import com.ukim.finki.develop.finkwave.repository.SongRepository;
+import com.ukim.finki.develop.finkwave.service.mappers.SongDetailsMapper;
 import lombok.AllArgsConstructor;
 import org.springframework.stereotype.Service;
@@ -14,4 +14,7 @@
     private final SongRepository songRepository;
     private final AuthService authService;
+    private final ArtistContributionService artistContributionService;
+    private final ReviewService reviewService;
+    private final SongDetailsMapper songDetailsMapper;
 
     public List<MusicalEntityDto> getTopSongs(){
@@ -32,3 +35,22 @@
         return songRepository.getRecentlyListened(userId);
     }
+
+    public MusicalEntityDto getSongById(Long songId){
+        Long userId = null;
+        try {
+            userId = authService.getCurrentUserID();
+        } catch (Exception ignored) {}
+        return songRepository.getSongById(songId, userId);
+    }
+
+    public SongDetailsDto getSongDetails(Long songId){
+        Long userId = null;
+        try {
+            userId = authService.getCurrentUserID();
+        } catch (Exception ignored){}
+        SongDto songDto = songRepository.getSongById(songId, userId);
+        List<ArtistContributionSummaryDto> contributionsBySongId = artistContributionService.getContributionsBySongId(songId);
+        List<ReviewDto> reviewsForSongId = reviewService.getReviewsForSongId(songId);
+        return songDetailsMapper.toSongDetailsDto(songDto, contributionsBySongId, reviewsForSongId);
+    }
 }
Index: finkwave/src/main/java/com/ukim/finki/develop/finkwave/service/mappers/SongDetailsMapper.java
===================================================================
--- finkwave/src/main/java/com/ukim/finki/develop/finkwave/service/mappers/SongDetailsMapper.java	(revision 8a47b30f7be0c80847e0bb6d30060d214d1bd85d)
+++ finkwave/src/main/java/com/ukim/finki/develop/finkwave/service/mappers/SongDetailsMapper.java	(revision 8a47b30f7be0c80847e0bb6d30060d214d1bd85d)
@@ -0,0 +1,28 @@
+package com.ukim.finki.develop.finkwave.service.mappers;
+
+import com.ukim.finki.develop.finkwave.model.dto.*;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+
+@Component
+public class SongDetailsMapper {
+    public SongDetailsDto toSongDetailsDto(SongDto songDto,
+                                           List<ArtistContributionSummaryDto> artistContributionSummaryDtos,
+                                           List<ReviewDto> reviewDtos){
+        SongDetailsDto songDetailsDto = new SongDetailsDto();
+        songDetailsDto.setId(songDto.getId());
+        songDetailsDto.setTitle(songDto.getTitle());
+        songDetailsDto.setAlbum(songDto.getAlbum());
+        songDetailsDto.setCover(songDto.getCover());
+        songDetailsDto.setGenre(songDto.getGenre());
+        songDetailsDto.setType(songDto.getType());
+        songDetailsDto.setAlbum(songDto.getAlbum());
+        songDetailsDto.setLink(songDto.getLink());
+        songDetailsDto.setIsLikedByCurrentUser(songDto.getIsLikedByCurrentUser());
+        songDetailsDto.setReleasedBy(songDto.getReleasedBy());
+        songDetailsDto.setContributions(artistContributionSummaryDtos);
+        songDetailsDto.setReviews(reviewDtos);
+        return songDetailsDto;
+    }
+}
Index: frontend/src/App.tsx
===================================================================
--- frontend/src/App.tsx	(revision dc30259a457c1232ee6ee1f6096c9fa50172e058)
+++ frontend/src/App.tsx	(revision 8a47b30f7be0c80847e0bb6d30060d214d1bd85d)
@@ -17,4 +17,5 @@
 import Nav from "./pages/Nav";
 import Register from "./pages/Register";
+import SongDetail from "./pages/SongDetail";
 import UserDetail from "./pages/UserDetail";
 
@@ -99,4 +100,8 @@
 			},
 			{
+				path: "/songs/:id",
+				element: <SongDetail />,
+			},
+			{
 				path: "/collection/:type/:id",
 				element: <MusicalCollection />,
Index: frontend/src/pages/SongDetail.tsx
===================================================================
--- frontend/src/pages/SongDetail.tsx	(revision 8a47b30f7be0c80847e0bb6d30060d214d1bd85d)
+++ frontend/src/pages/SongDetail.tsx	(revision 8a47b30f7be0c80847e0bb6d30060d214d1bd85d)
@@ -0,0 +1,394 @@
+import { useEffect, useState } from "react";
+import { Link, useParams } from "react-router-dom";
+import axiosInstance from "../api/axiosInstance";
+import { useAuth } from "../context/authContext";
+import type { SongDetail as SongDetailType } from "../utils/types";
+
+const ROLE_LABELS: Record<string, string> = {
+	MAIN_VOCAL: "Main Vocal",
+	FEATURED: "Featured",
+	PRODUCER: "Producer",
+	SONGWRITER: "Songwriter",
+	COMPOSER: "Composer",
+	MIXER: "Mixer",
+	ENGINEER: "Engineer",
+};
+
+const formatRole = (role: string): string => {
+	return ROLE_LABELS[role] || role.replace(/_/g, " ");
+};
+
+// convert a regular youtube URL to an embeddable URL
+const toEmbedUrl = (url: string): string => {
+	try {
+		const parsed = new URL(url);
+		// youtube.com/watch?v=ID
+		if (
+			(parsed.hostname === "www.youtube.com" ||
+				parsed.hostname === "youtube.com") &&
+			parsed.searchParams.has("v")
+		) {
+			return `https://www.youtube.com/embed/${parsed.searchParams.get("v")}`;
+		}
+		// youtu.be/ID
+		if (parsed.hostname === "youtu.be") {
+			return `https://www.youtube.com/embed${parsed.pathname}`;
+		}
+		// already an embed URL or other provider – return as-is
+		return url;
+	} catch {
+		return url;
+	}
+};
+
+const renderStars = (grade: number) => {
+	return (
+		<div className="flex gap-0.5">
+			{[1, 2, 3, 4, 5].map((star) => (
+				<svg
+					key={star}
+					className={`w-4 h-4 ${star <= grade ? "text-yellow-400" : "text-gray-600"}`}
+					fill="currentColor"
+					viewBox="0 0 20 20"
+				>
+					<path d="M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z" />
+				</svg>
+			))}
+		</div>
+	);
+};
+
+const SongDetail = () => {
+	const { id } = useParams<{ id: string }>();
+	const { user } = useAuth();
+	const [song, setSong] = useState<SongDetailType | null>(null);
+	const [loading, setLoading] = useState(true);
+	const [error, setError] = useState<string | null>(null);
+
+	useEffect(() => {
+		const fetchSong = async () => {
+			try {
+				setLoading(true);
+				const response = await axiosInstance.get(`/songs/${id}/details`);
+				setSong(response.data);
+			} catch (err) {
+				console.error("Error fetching song details:", err);
+				setError("Failed to load song details.");
+			} finally {
+				setLoading(false);
+			}
+		};
+		if (id) fetchSong();
+	}, [id]);
+
+	const toggleLike = async () => {
+		if (!song) return;
+		try {
+			await axiosInstance.post(`/musical-entity/${song.id}/like`);
+			setSong((prev) =>
+				prev
+					? { ...prev, isLikedByCurrentUser: !prev.isLikedByCurrentUser }
+					: prev,
+			);
+		} catch (err) {
+			console.error("Error toggling like:", err);
+		}
+	};
+
+	if (loading) {
+		return (
+			<div className="min-h-screen bg-linear-to-br from-[#1e1e2e] to-[#0f0f1e] flex items-center justify-center">
+				<div className="flex flex-col items-center gap-4">
+					<div className="w-12 h-12 border-4 border-white/10 border-t-[#1db954] rounded-full animate-spin" />
+					<p className="text-gray-400 text-lg">Loading song…</p>
+				</div>
+			</div>
+		);
+	}
+
+	if (error || !song) {
+		return (
+			<div className="min-h-screen bg-linear-to-br from-[#1e1e2e] to-[#0f0f1e] flex items-center justify-center">
+				<div className="text-center">
+					<p className="text-red-400 text-xl mb-4">
+						{error ?? "Song not found"}
+					</p>
+					<Link to="/" className="text-[#1db954] hover:underline text-sm">
+						← Back to Home
+					</Link>
+				</div>
+			</div>
+		);
+	}
+
+	const otherContributors = song.contributions.filter(
+		(c) => c.artistName !== song.releasedBy,
+	);
+
+	const avgRating =
+		song.reviews.length > 0
+			? (
+					song.reviews.reduce((sum, r) => sum + r.grade, 0) /
+					song.reviews.length
+				).toFixed(1)
+			: null;
+
+	return (
+		<div className="min-h-screen bg-linear-to-br from-[#1e1e2e] to-[#0f0f1e] text-white">
+			<div className="max-w-5xl mx-auto px-6 py-10">
+				{/* Back link */}
+				<Link
+					to="/"
+					className="inline-flex items-center gap-1 text-gray-400 hover:text-white text-sm mb-8 transition-colors"
+				>
+					<svg
+						className="w-4 h-4"
+						fill="none"
+						stroke="currentColor"
+						viewBox="0 0 24 24"
+					>
+						<path
+							strokeLinecap="round"
+							strokeLinejoin="round"
+							strokeWidth={2}
+							d="M15 19l-7-7 7-7"
+						/>
+					</svg>
+					Back to Home
+				</Link>
+
+				{/* Hero section */}
+				<div className="flex flex-col md:flex-row gap-8 mb-10">
+					{/* Cover art */}
+					<div className="w-full md:w-72 shrink-0">
+						<div className="relative w-full pt-[100%] rounded-xl overflow-hidden shadow-2xl bg-[#181818]">
+							<img
+								src={song.cover || "/favicon.png"}
+								alt={song.title}
+								className="absolute inset-0 w-full h-full object-cover"
+								onError={(e) => {
+									(e.target as HTMLImageElement).src = "/favicon.png";
+								}}
+							/>
+						</div>
+					</div>
+
+					{/* Song info */}
+					<div className="flex flex-col justify-end gap-3 min-w-0">
+						<span className="text-xs uppercase tracking-widest text-gray-400 font-medium">
+							{song.genre} • Song
+						</span>
+						<h1 className="text-4xl md:text-5xl font-extrabold leading-tight truncate">
+							{song.title}
+						</h1>
+
+						{/* Main artist */}
+						<p className="text-xl text-gray-300 font-semibold">
+							{song.releasedBy}
+						</p>
+
+						{/* Album */}
+						{song.album && (
+							<p className="text-sm text-gray-500">
+								Album: <span className="text-gray-300">{song.album}</span>
+							</p>
+						)}
+
+						{/* Rating summary */}
+						{avgRating && (
+							<div className="flex items-center gap-2 mt-1">
+								{renderStars(Math.round(Number(avgRating)))}
+								<span className="text-sm text-gray-400">
+									{avgRating} · {song.reviews.length}{" "}
+									{song.reviews.length === 1 ? "review" : "reviews"}
+								</span>
+							</div>
+						)}
+
+						{/* Action buttons */}
+						{/* todo: add add to playlist button */}
+						<div className="flex items-center gap-3 mt-4">
+							{user && (
+								<button
+									onClick={toggleLike}
+									className={`flex items-center gap-2 px-5 py-2.5 rounded-full text-sm font-semibold transition-colors cursor-pointer ${
+										song.isLikedByCurrentUser
+											? "bg-[#1db954] text-black"
+											: "bg-white/10 text-white hover:bg-white/20"
+									}`}
+								>
+									{song.isLikedByCurrentUser ? (
+										<svg
+											className="w-5 h-5"
+											fill="currentColor"
+											viewBox="0 0 24 24"
+										>
+											<path d="M12 21.35l-1.45-1.32C5.4 15.36 2 12.28 2 8.5 2 5.42 4.42 3 7.5 3c1.74 0 3.41.81 4.5 2.09C13.09 3.81 14.76 3 16.5 3 19.58 3 22 5.42 22 8.5c0 3.78-3.4 6.86-8.55 11.54L12 21.35z" />
+										</svg>
+									) : (
+										<svg
+											className="w-5 h-5"
+											fill="none"
+											stroke="currentColor"
+											viewBox="0 0 24 24"
+										>
+											<path
+												strokeLinecap="round"
+												strokeLinejoin="round"
+												strokeWidth={2}
+												d="M4.318 6.318a4.5 4.5 0 000 6.364L12 20.364l7.682-7.682a4.5 4.5 0 00-6.364-6.364L12 7.636l-1.318-1.318a4.5 4.5 0 00-6.364 0z"
+											/>
+										</svg>
+									)}
+									{song.isLikedByCurrentUser ? "Liked" : "Like"}
+								</button>
+							)}
+						</div>
+					</div>
+				</div>
+
+				{/* YouTube embed */}
+				{song.link && (
+					<section className="mb-10">
+						<div className="rounded-xl overflow-hidden shadow-lg aspect-video bg-black">
+							<iframe
+								src={toEmbedUrl(song.link)}
+								title={song.title}
+								className="w-full h-full"
+								allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
+								allowFullScreen
+							/>
+						</div>
+					</section>
+				)}
+
+				{/* Credits / Contributions */}
+				{song.contributions.length > 0 && (
+					<section className="mb-10">
+						<h2 className="text-2xl font-bold mb-4">Credits</h2>
+						<div className="bg-[#1a1a2e]/60 rounded-xl p-5 divide-y divide-white/5">
+							{/* Main artist first */}
+							{song.contributions
+								.filter((c) => c.artistName === song.releasedBy)
+								.map((c, i) => (
+									<div
+										key={`main-${i}`}
+										className="flex items-center justify-between py-3 first:pt-0 last:pb-0"
+									>
+										<div className="flex items-center gap-3">
+											<div className="w-10 h-10 bg-[#1db954] rounded-full flex items-center justify-center text-black font-bold text-sm">
+												{c.artistName.charAt(0).toUpperCase()}
+											</div>
+											<div>
+												<p className="text-white font-semibold text-lg">
+													{c.artistName}
+												</p>
+											</div>
+										</div>
+										<span className="text-sm text-gray-400 bg-white/5 px-3 py-1 rounded-full">
+											{formatRole(c.role)}
+										</span>
+									</div>
+								))}
+
+							{/* Other contributors */}
+							{otherContributors.map((c, i) => (
+								<div
+									key={`contrib-${i}`}
+									className="flex items-center justify-between py-3 first:pt-0 last:pb-0"
+								>
+									<div className="flex items-center gap-3">
+										<div className="w-9 h-9 bg-white/10 rounded-full flex items-center justify-center text-white font-medium text-sm">
+											{c.artistName.charAt(0).toUpperCase()}
+										</div>
+										<p className="text-gray-300 font-medium">{c.artistName}</p>
+									</div>
+									<span className="text-sm text-gray-500 bg-white/5 px-3 py-1 rounded-full">
+										{formatRole(c.role)}
+									</span>
+								</div>
+							))}
+						</div>
+					</section>
+				)}
+
+				{/* Reviews */}
+				<section>
+					<div className="flex items-center justify-between mb-4">
+						<h2 className="text-2xl font-bold">
+							Reviews
+							{song.reviews.length > 0 && (
+								<span className="text-base font-normal text-gray-500 ml-2">
+									({song.reviews.length})
+								</span>
+							)}
+						</h2>
+						<button
+							onClick={() => {
+								/* TODO: add review modal */
+							}}
+							className="flex items-center gap-2 bg-[#1db954] hover:bg-[#1ed760] text-black text-sm font-semibold px-4 py-2 rounded-full transition-colors"
+						>
+							<svg
+								className="w-4 h-4"
+								fill="none"
+								stroke="currentColor"
+								viewBox="0 0 24 24"
+							>
+								<path
+									strokeLinecap="round"
+									strokeLinejoin="round"
+									strokeWidth={2}
+									d="M12 4v16m8-8H4"
+								/>
+							</svg>
+							Add Review
+						</button>
+					</div>
+
+					{song.reviews.length === 0 ? (
+						<div className="bg-[#1a1a2e]/60 rounded-xl p-10 text-center">
+							<p className="text-gray-500 text-lg">No reviews yet.</p>
+							<p className="text-gray-600 text-sm mt-1">
+								Be the first to share your thoughts!
+							</p>
+						</div>
+					) : (
+						<div className="space-y-4">
+							{song.reviews.map((review) => (
+								<div
+									key={`${review.id.listenerId}-${review.id.musicalEntityId}`}
+									className="bg-[#1a1a2e]/60 rounded-xl p-5 hover:bg-[#1a1a2e]/80 transition-colors"
+								>
+									<div className="flex items-start justify-between mb-2">
+										<div className="flex items-center gap-3">
+											<div className="w-9 h-9 bg-blue-500/20 rounded-full flex items-center justify-center">
+												<span className="text-blue-400 font-semibold text-sm">
+													{review.author.charAt(0).toUpperCase()}
+												</span>
+											</div>
+											<div>
+												<p className="text-white font-medium">
+													{review.author}
+												</p>
+												{renderStars(review.grade)}
+											</div>
+										</div>
+										<span className="text-sm text-gray-500 bg-white/5 px-2.5 py-0.5 rounded-full">
+											{review.grade}/5
+										</span>
+									</div>
+									<p className="text-gray-300 text-sm leading-relaxed mt-3 pl-12">
+										{review.comment}
+									</p>
+								</div>
+							))}
+						</div>
+					)}
+				</section>
+			</div>
+		</div>
+	);
+};
+
+export default SongDetail;
Index: frontend/src/utils/types.ts
===================================================================
--- frontend/src/utils/types.ts	(revision dc30259a457c1232ee6ee1f6096c9fa50172e058)
+++ frontend/src/utils/types.ts	(revision 8a47b30f7be0c80847e0bb6d30060d214d1bd85d)
@@ -64,4 +64,27 @@
 }
 
+export interface SongContribution {
+	artistName: string;
+	role: string;
+}
+
+export interface SongReview {
+	id: {
+		listenerId: number;
+		musicalEntityId: number;
+	};
+	author: string;
+	grade: number;
+	comment: string;
+}
+
+export interface SongDetail extends MusicalEntity {
+	type: "SONG";
+	album?: string | null;
+	link?: string | null;
+	contributions: SongContribution[];
+	reviews: SongReview[];
+}
+
 export interface BasicSong {
 	id: number;
