Index: KernelRecordsMVC.Web/Controllers/AdminController.cs
===================================================================
--- KernelRecordsMVC.Web/Controllers/AdminController.cs	(revision d2eccb3e3d4db7d262fc57179b8ce6f7fb060d63)
+++ KernelRecordsMVC.Web/Controllers/AdminController.cs	(revision d89d25b3a7f785676877cf198c9cc706308ab4a3)
@@ -1150,3 +1150,477 @@
         _context.SaveChanges();
     }
+    // =========================================================
+// ARTISTS
+// =========================================================
+
+[HttpGet]
+public IActionResult Artists()
+{
+    if (!IsAdmin())
+        return Forbid();
+
+    var artists = _context.Artists
+        .OrderBy(a => a.ArtistName)
+        .ToList();
+
+    return View(artists);
 }
+
+
+// =========================================================
+// CREATE ARTIST - GET
+// =========================================================
+
+[HttpGet]
+public IActionResult CreateArtist()
+{
+    if (!IsAdmin())
+        return Forbid();
+
+    return View(new CreateArtistViewModel());
+}
+
+
+// =========================================================
+// CREATE ARTIST - POST
+// =========================================================
+
+[HttpPost]
+[ValidateAntiForgeryToken]
+public IActionResult CreateArtist(CreateArtistViewModel model)
+{
+    if (!IsAdmin())
+        return Forbid();
+
+    if (!ModelState.IsValid)
+        return View(model);
+
+    var duplicateExists =
+        _context.Artists.Any(a =>
+            a.ArtistName.ToLower() ==
+            model.ArtistName.Trim().ToLower());
+
+    if (duplicateExists)
+    {
+        ModelState.AddModelError(
+            nameof(model.ArtistName),
+            "An artist with this name already exists.");
+
+        return View(model);
+    }
+
+    var artist = new Artist
+    {
+        ArtistId = GetNextArtistId(),
+
+        ArtistName =
+            model.ArtistName.Trim(),
+
+        ArtistDescription =
+            string.IsNullOrWhiteSpace(model.ArtistDescription)
+                ? null
+                : model.ArtistDescription.Trim(),
+
+        ArtistPhoto =
+            string.IsNullOrWhiteSpace(model.ArtistPhoto)
+                ? null
+                : model.ArtistPhoto.Trim()
+    };
+
+    _context.Artists.Add(artist);
+    _context.SaveChanges();
+
+    TempData["Success"] =
+        $"{artist.ArtistName} was created successfully.";
+
+    return RedirectToAction(nameof(Artists));
+}
+
+
+// =========================================================
+// EDIT ARTIST - GET
+// =========================================================
+
+[HttpGet]
+public IActionResult EditArtist(long id)
+{
+    if (!IsAdmin())
+        return Forbid();
+
+    var artist = _context.Artists
+        .FirstOrDefault(a =>
+            a.ArtistId == id);
+
+    if (artist == null)
+        return NotFound();
+
+    var model = new EditArtistViewModel
+    {
+        ArtistId =
+            artist.ArtistId,
+
+        ArtistName =
+            artist.ArtistName,
+
+        ArtistDescription =
+            artist.ArtistDescription,
+
+        ArtistPhoto =
+            artist.ArtistPhoto
+    };
+
+    return View(model);
+}
+
+
+// =========================================================
+// EDIT ARTIST - POST
+// =========================================================
+
+[HttpPost]
+[ValidateAntiForgeryToken]
+public IActionResult EditArtist(EditArtistViewModel model)
+{
+    if (!IsAdmin())
+        return Forbid();
+
+    var artist = _context.Artists
+        .FirstOrDefault(a =>
+            a.ArtistId == model.ArtistId);
+
+    if (artist == null)
+        return NotFound();
+
+    if (!ModelState.IsValid)
+        return View(model);
+
+    var duplicateExists =
+        _context.Artists.Any(a =>
+            a.ArtistId != model.ArtistId &&
+            a.ArtistName.ToLower() ==
+            model.ArtistName.Trim().ToLower());
+
+    if (duplicateExists)
+    {
+        ModelState.AddModelError(
+            nameof(model.ArtistName),
+            "Another artist already uses this name.");
+
+        return View(model);
+    }
+
+    artist.ArtistName =
+        model.ArtistName.Trim();
+
+    artist.ArtistDescription =
+        string.IsNullOrWhiteSpace(model.ArtistDescription)
+            ? null
+            : model.ArtistDescription.Trim();
+
+    artist.ArtistPhoto =
+        string.IsNullOrWhiteSpace(model.ArtistPhoto)
+            ? null
+            : model.ArtistPhoto.Trim();
+
+    _context.Artists.Update(artist);
+    _context.SaveChanges();
+
+    TempData["Success"] =
+        $"{artist.ArtistName} was updated successfully.";
+
+    return RedirectToAction(nameof(Artists));
+}
+private long GetNextArtistId()
+{
+    var maxId = _context.Artists
+        .Select(x => (long?)x.ArtistId)
+        .Max();
+
+    return (maxId ?? 0) + 1;
+}
+// =========================================================
+// RELEASES
+// =========================================================
+
+[HttpGet]
+public IActionResult Releases()
+{
+    if (!IsAdmin())
+        return Forbid();
+
+    var releases = _context.Releases
+        .Include(r => r.ReleaseArtists)
+            .ThenInclude(ra => ra.Artist)
+        .OrderBy(r => r.Title)
+        .ToList();
+
+    return View(releases);
+}
+
+
+// =========================================================
+// EDIT RELEASE - GET
+// =========================================================
+
+    [HttpGet]
+    public IActionResult EditRelease(long id)
+    {
+        if (!IsAdmin())
+            return Forbid();
+
+
+        var release = _context.Releases
+            .Include(r => r.ReleaseArtists)
+            .ThenInclude(ra => ra.Artist)
+            .FirstOrDefault(r =>
+                r.ReleaseId == id);
+
+
+        if (release == null)
+            return NotFound();
+
+
+        var mainArtist = release.ReleaseArtists
+            .FirstOrDefault(ra =>
+                ra.Type == ArtistReleaseType.MAIN);
+
+
+        var featuredArtists = release.ReleaseArtists
+            .Where(ra =>
+                ra.Type == ArtistReleaseType.FEATURE)
+            .OrderBy(ra => ra.ReleaseOrdinal)
+            .Select(ra => ra.ArtistId)
+            .ToList();
+
+
+        var model = new EditReleaseViewModel
+        {
+            ReleaseId =
+                release.ReleaseId,
+
+            Title =
+                release.Title,
+
+            RecordLabel =
+                release.RecordLabel,
+
+            Genre =
+                release.Genre,
+
+            ReleaseDate =
+                release.ReleaseDate,
+
+            CoverPhoto =
+                release.CoverPhoto,
+
+            MainArtistId =
+                mainArtist?.ArtistId ?? 0,
+
+            FeaturedArtistIds =
+                featuredArtists
+        };
+
+
+        LoadArtists();
+
+
+        return View(model);
+    }
+
+
+// =========================================================
+// EDIT RELEASE - POST
+// =========================================================
+
+[HttpPost]
+[ValidateAntiForgeryToken]
+public IActionResult EditRelease(
+    EditReleaseViewModel model)
+{
+    if (!IsAdmin())
+        return Forbid();
+
+
+    var release = _context.Releases
+        .Include(r => r.ReleaseArtists)
+        .FirstOrDefault(r =>
+            r.ReleaseId == model.ReleaseId);
+
+
+    if (release == null)
+        return NotFound();
+
+
+    // ==========================================
+    // ARTIST VALIDATION
+    // ==========================================
+
+    var mainArtistExists =
+        _context.Artists.Any(a =>
+            a.ArtistId == model.MainArtistId);
+
+
+    if (!mainArtistExists)
+    {
+        ModelState.AddModelError(
+            nameof(model.MainArtistId),
+            "Please select a valid main artist.");
+    }
+
+
+    model.FeaturedArtistIds ??=
+        new List<long>();
+
+
+    model.FeaturedArtistIds =
+        model.FeaturedArtistIds
+            .Distinct()
+            .Where(id =>
+                id != model.MainArtistId)
+            .ToList();
+
+
+    if (model.FeaturedArtistIds.Count > 0)
+    {
+        var validFeaturedCount =
+            _context.Artists.Count(a =>
+                model.FeaturedArtistIds
+                    .Contains(a.ArtistId));
+
+
+        if (validFeaturedCount !=
+            model.FeaturedArtistIds.Count)
+        {
+            ModelState.AddModelError(
+                nameof(model.FeaturedArtistIds),
+                "One or more featured artists are invalid.");
+        }
+    }
+
+
+    if (!ModelState.IsValid)
+    {
+        LoadArtists();
+
+        return View(model);
+    }
+
+
+    using var transaction =
+        _context.Database.BeginTransaction();
+
+
+    try
+    {
+        // ==========================================
+        // UPDATE RELEASE INFORMATION
+        // ==========================================
+
+        release.Title =
+            model.Title.Trim();
+
+        release.RecordLabel =
+            string.IsNullOrWhiteSpace(
+                model.RecordLabel)
+                ? null
+                : model.RecordLabel.Trim();
+
+        release.Genre =
+            model.Genre.Trim();
+
+        release.ReleaseDate =
+            model.ReleaseDate;
+
+        release.CoverPhoto =
+            model.CoverPhoto.Trim();
+
+
+        _context.Releases.Update(
+            release);
+
+
+        // ==========================================
+        // REMOVE OLD RELEASE ARTIST LINKS
+        // ==========================================
+
+        var existingArtistLinks =
+            release.ReleaseArtists.ToList();
+
+
+        _context.ReleaseArtists.RemoveRange(
+            existingArtistLinks);
+
+
+        _context.SaveChanges();
+
+
+        // ==========================================
+        // ADD MAIN ARTIST
+        // ==========================================
+
+        _context.ReleaseArtists.Add(
+            new ReleaseArtist
+            {
+                ReleaseId =
+                    release.ReleaseId,
+
+                ArtistId =
+                    model.MainArtistId,
+
+                ReleaseOrdinal =
+                    1,
+
+                Type =
+                    ArtistReleaseType.MAIN
+            });
+
+
+        // ==========================================
+        // ADD FEATURED ARTISTS
+        // ==========================================
+
+        long ordinal = 2;
+
+
+        foreach (var artistId
+                 in model.FeaturedArtistIds)
+        {
+            _context.ReleaseArtists.Add(
+                new ReleaseArtist
+                {
+                    ReleaseId =
+                        release.ReleaseId,
+
+                    ArtistId =
+                        artistId,
+
+                    ReleaseOrdinal =
+                        ordinal++,
+
+                    Type =
+                        ArtistReleaseType.FEATURE
+                });
+        }
+
+
+        _context.SaveChanges();
+
+
+        transaction.Commit();
+
+
+        TempData["Success"] =
+            $"{release.Title} was updated successfully.";
+
+
+        return RedirectToAction(
+            nameof(Releases));
+    }
+    catch
+    {
+        transaction.Rollback();
+
+        throw;
+    }
+}
+}
Index: KernelRecordsMVC.Web/Controllers/ArtistController.cs
===================================================================
--- KernelRecordsMVC.Web/Controllers/ArtistController.cs	(revision d89d25b3a7f785676877cf198c9cc706308ab4a3)
+++ KernelRecordsMVC.Web/Controllers/ArtistController.cs	(revision d89d25b3a7f785676877cf198c9cc706308ab4a3)
@@ -0,0 +1,51 @@
+﻿using KernelRecordsMVC.Infrastructure.Data;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.EntityFrameworkCore;
+
+namespace KernelRecordsMVC.Web.Controllers;
+
+public class ArtistController : Controller
+{
+    private readonly KernelRecordsContext _context;
+
+    public ArtistController(KernelRecordsContext context)
+    {
+        _context = context;
+    }
+
+
+    // =========================================================
+    // ARTIST LIST
+    // =========================================================
+
+    [HttpGet]
+    public IActionResult Index()
+    {
+        var artists = _context.Artists
+            .OrderBy(a => a.ArtistName)
+            .ToList();
+
+        return View(artists);
+    }
+
+
+    // =========================================================
+    // ARTIST DETAILS
+    // =========================================================
+
+    [HttpGet]
+    public IActionResult Details(long id)
+    {
+        var artist = _context.Artists
+            .Include(a => a.ReleaseArtists)
+            .ThenInclude(ra => ra.Release)
+            .ThenInclude(r => r.Products)
+            .FirstOrDefault(a =>
+                a.ArtistId == id);
+
+        if (artist == null)
+            return NotFound();
+
+        return View(artist);
+    }
+}
Index: KernelRecordsMVC.Web/Controllers/WishlistController.cs
===================================================================
--- KernelRecordsMVC.Web/Controllers/WishlistController.cs	(revision d2eccb3e3d4db7d262fc57179b8ce6f7fb060d63)
+++ KernelRecordsMVC.Web/Controllers/WishlistController.cs	(revision d89d25b3a7f785676877cf198c9cc706308ab4a3)
@@ -54,16 +54,22 @@
     public IActionResult Add(long productId)
     {
-        var userId = GetUserId();
-
-        if (userId == null)
-        {
-            return RedirectToAction(
-                "Login",
-                "Account");
-        }
-
-        var product = _context.Products
-            .Include(p => p.Release)
-            .FirstOrDefault(p => p.ProductId == productId);
+        var sessionUserId =
+            HttpContext.Session.GetInt32("UserId");
+
+        if (!sessionUserId.HasValue)
+        {
+            return RedirectToAction(
+                "Login",
+                "Account");
+        }
+
+        var userId =
+            (long)sessionUserId.Value;
+
+
+        var product =
+            _context.Products
+                .FirstOrDefault(p =>
+                    p.ProductId == productId);
 
         if (product == null)
@@ -71,54 +77,66 @@
 
 
-        // Find existing wishlist
-        var wishlist = _context.Wishlists
-            .Include(w => w.WishlistProducts)
-            .FirstOrDefault(w =>
-                w.UserId == userId.Value);
-
-
-        // Create wishlist if user doesn't have one
+        var wishlist =
+            _context.Wishlists
+                .FirstOrDefault(w =>
+                    w.UserId == userId);
+
+
+        // Create wishlist if user doesn't have one yet.
         if (wishlist == null)
         {
             wishlist = new Wishlist
             {
-                WishlistId = GetNextWishlistId(),
-                UserId = userId.Value
+                WishlistId =
+                    GetNextWishlistId(),
+
+                UserId =
+                    userId
             };
 
-            _context.Wishlists.Add(wishlist);
+
+            _context.Wishlists.Add(
+                wishlist);
+
             _context.SaveChanges();
         }
 
 
-        // Check if product is already there
-        var alreadyExists = wishlist.WishlistProducts
-            .Any(x => x.ProductId == productId);
+        // Prevent duplicate product.
+        var alreadyExists =
+            _context.WishlistProducts
+                .Any(wp =>
+                    wp.WishlistId ==
+                    wishlist.WishlistId &&
+                    wp.ProductId ==
+                    productId);
+
 
         if (!alreadyExists)
         {
-            var wishlistProduct = new WishlistProduct
-            {
-                WishlistId = wishlist.WishlistId,
-                ProductId = productId,
-                AddedAt = DateTime.Today
-            };
-
-            _context.WishlistProducts.Add(wishlistProduct);
+            var wishlistProduct =
+                new WishlistProduct
+                {
+                    WishlistId =
+                        wishlist.WishlistId,
+
+                    ProductId =
+                        productId
+                };
+
+
+            _context.WishlistProducts.Add(
+                wishlistProduct);
+
             _context.SaveChanges();
-
-            TempData["Success"] =
-                "Product added to your wishlist.";
-        }
-        else
-        {
-            TempData["Info"] =
-                "This product is already in your wishlist.";
-        }
+        }
+
+
+        TempData["Success"] =
+            "Product added to your wishlist.";
+
 
         return RedirectToAction(
-            "Details",
-            "Release",
-            new { id = product.ReleaseId });
+            nameof(Index));
     }
 
