Claude-skill-registry implement-track-management
Plan and implement Stage 5 Track Management with CRUD endpoints, soft-delete, and lifecycle worker (plan)
install
source · Clone the upstream repo
git clone https://github.com/majiayu000/claude-skill-registry
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/implement-track-management" ~/.claude/skills/majiayu000-claude-skill-registry-implement-track-management && rm -rf "$T"
manifest:
skills/data/implement-track-management/SKILL.mdsource content
Implement Track Management Skill
Plan and implement Stage 5 Track Management for NovaTune: CRUD endpoints, soft-delete semantics, lifecycle worker, and observability.
Overview
Stage 5 implements user library management with:
- GET /tracks - List tracks with search, filter, sort, cursor-based pagination
- GET /tracks/{trackId} - Get track details
- PATCH /tracks/{trackId} - Update track metadata (merge policy)
- DELETE /tracks/{trackId} - Soft-delete with grace period
- POST /tracks/{trackId}/restore - Restore within grace period
- Lifecycle Worker - Physical deletion after grace period
Implementation Plan
Phase 1: Models and Configuration
-
Extend Track Model (
)ApiService/Models/Track.cs- Add soft-delete fields:
,DeletedAt
,ScheduledDeletionAtStatusBeforeDeletion
- Add soft-delete fields:
-
Add Configuration (
)ApiService/Configuration/TrackManagementOptions.cs
(default: 30 days)DeletionGracePeriod
(default: 100)MaxPageSize
(default: 20)DefaultPageSize
-
Add DTOs (
)ApiService/Models/
,TrackListQueryTrackListQueryParams
,TrackListItemTrackDetailsUpdateTrackRequest
,PagedResult<T>TrackListCursor
Phase 2: RavenDB Indexes
-
Tracks_ByUserForSearch (
)ApiService/Infrastructure/Indexes/Map = tracks => from track in tracks where track.Status != TrackStatus.Unknown select new { track.UserId, track.Status, track.Title, track.Artist, track.CreatedAt, track.UpdatedAt, track.Duration, SearchText = new[] { track.Title, track.Artist } }; Index("SearchText", FieldIndexing.Search); -
Tracks_ByScheduledDeletion (
)ApiService/Infrastructure/Indexes/Map = tracks => from track in tracks where track.Status == TrackStatus.Deleted && track.ScheduledDeletionAt != null select new { track.Status, track.ScheduledDeletionAt };
Phase 3: Service Layer
-
ITrackManagementService (
)ApiService/Services/ListTracksAsync(userId, query, ct)GetTrackAsync(trackId, userId, ct)UpdateTrackAsync(trackId, userId, request, ct)DeleteTrackAsync(trackId, userId, ct)RestoreTrackAsync(trackId, userId, ct)
-
Custom Exceptions (
)ApiService/Infrastructure/Exceptions/TrackNotFoundExceptionTrackAccessDeniedExceptionTrackDeletedExceptionRestorationExpiredException
Phase 4: API Endpoints
-
TrackEndpoints.cs (
)ApiService/Endpoints/group.MapGet("/", HandleListTracks).RequireRateLimiting("track-list"); group.MapGet("/{trackId}", HandleGetTrack); group.MapPatch("/{trackId}", HandleUpdateTrack).RequireRateLimiting("track-update"); group.MapDelete("/{trackId}", HandleDeleteTrack).RequireRateLimiting("track-delete"); group.MapPost("/{trackId}/restore", HandleRestoreTrack); -
Rate Limiting Policies
: 60 req/mintrack-list
: 30 req/mintrack-update
: 10 req/mintrack-delete
Phase 5: Event Publishing
-
TrackDeletedEvent (
)ApiService/Infrastructure/Messaging/Messages/- Migrate from Guid to ULID strings
- Include
,ObjectKey
,WaveformObjectKeyFileSizeBytes
-
Outbox Pattern
- Write event to
collection in same transactionOutboxMessages - Outbox processor publishes to
topic{prefix}-track-deletions
- Write event to
Phase 6: Lifecycle Worker
-
Create Worker Project (
)Workers.Lifecycle/- Use
skilladd-aspire-worker-project
- Use
-
TrackDeletedHandler - Kafka consumer for immediate cache invalidation
-
PhysicalDeletionService - Background service polling for expired tracks
- Delete MinIO objects (audio + waveform)
- Delete RavenDB document
- Update user quota
Phase 7: Observability
-
Metrics (
)ApiService/Infrastructure/Observability/track_list_requests_totaltrack_get_requests_totaltrack_update_requests_totaltrack_delete_requests_totaltrack_physical_deletions_total
-
Logging
- Track operations with
,TrackId
,UserIdCorrelationId - Never log object keys in production
- Track operations with
Phase 8: Testing
-
Unit Tests
TrackManagementServiceTests- Pagination cursor encoding/decoding
- Soft-delete state transitions
-
Integration Tests
- End-to-end CRUD flow
- Soft-delete → restore → delete cycle
- Physical deletion via lifecycle worker
Files to Create/Modify
New Files
| File | Purpose |
|---|---|
| Configuration |
| Service interface |
| Service implementation |
| API endpoints |
| Query model |
| Pagination result |
| Search index |
| Deletion index |
| Custom exceptions |
| New worker project |
Modified Files
| File | Changes |
|---|---|
| Add soft-delete fields |
| Register services, rate limiting |
| Add lifecycle worker |
Related Skills
- add-ravendb-index - For creating RavenDB indexes
- add-rate-limiting - For rate limiting policies
- add-background-service - For physical deletion service
- add-kafka-consumer - For TrackDeletedHandler
- add-aspire-worker-project - For lifecycle worker project
- add-observability - For metrics and tracing
Validation Checklist
- All CRUD endpoints return RFC 7807 problem details on error
- Rate limiting enforced on mutation endpoints
- Soft-delete preserves
for restoreStatusBeforeDeletion - Physical deletion only after grace period
- Cache invalidated immediately on soft-delete
- Quota updated only after physical deletion
- All operations logged with correlation ID
- Optimistic concurrency on updates