---
description: Add and remove tracks from playlists with position management and validation (project)
---
# Add Playlist Tracks Skill
Implement adding and removing tracks from playlists with ownership validation, position management, and quota enforcement.
## Overview
Playlist track management involves:
- Adding tracks at specific positions (or appending)
- Removing tracks by position
- Validating track ownership and status
- Enforcing track limits per playlist
- Maintaining position integrity
## Steps
### 1. Create Request Models
Location: `src/NovaTuneApp/NovaTuneApp.ApiService/Models/Playlists/`
```csharp
namespace NovaTuneApp.ApiService.Models.Playlists;
///
/// Request to add tracks to a playlist.
///
/// Track IDs to add (1-100 per request)
/// Insert position (null = append to end)
public record AddTracksRequest(
IReadOnlyList TrackIds,
int? Position = null);
```
### 2. Add Validation
Location: `src/NovaTuneApp/NovaTuneApp.ApiService/Validators/`
```csharp
using FluentValidation;
namespace NovaTuneApp.ApiService.Validators;
public class AddTracksRequestValidator : AbstractValidator
{
public AddTracksRequestValidator(IOptions options)
{
RuleFor(x => x.TrackIds)
.NotEmpty()
.WithMessage("At least one track ID is required")
.Must(ids => ids.Count <= options.Value.MaxTracksPerAddRequest)
.WithMessage($"Maximum {options.Value.MaxTracksPerAddRequest} tracks per request");
RuleForEach(x => x.TrackIds)
.Must(id => Ulid.TryParse(id, out _))
.WithMessage("Track ID must be a valid ULID");
RuleFor(x => x.Position)
.GreaterThanOrEqualTo(0)
.When(x => x.Position.HasValue)
.WithMessage("Position must be non-negative");
}
}
```
### 3. Implement Add Tracks in Service
Location: `src/NovaTuneApp/NovaTuneApp.ApiService/Services/PlaylistService.cs`
```csharp
public async Task AddTracksAsync(
string playlistId,
string userId,
AddTracksRequest request,
CancellationToken ct = default)
{
var playlist = await _session.LoadAsync($"Playlists/{playlistId}", ct);
if (playlist is null)
throw new PlaylistNotFoundException(playlistId);
if (playlist.UserId != userId)
throw new PlaylistAccessDeniedException(playlistId);
// Check track limit
if (playlist.TrackCount + request.TrackIds.Count > _options.Value.MaxTracksPerPlaylist)
{
throw new PlaylistTrackLimitExceededException(
playlistId,
playlist.TrackCount,
request.TrackIds.Count,
_options.Value.MaxTracksPerPlaylist);
}
// Load and validate all tracks
var trackDocIds = request.TrackIds.Select(id => $"Tracks/{id}").ToList();
var trackDocs = await _session.LoadAsync