chore: group .NET into backend/ and drop non-.NET test artifacts

- Move all .NET (6 projects, solution, Directory.*.props, nuget.config)
  into backend/ so the monorepo root can host non-.NET projects later
- Remove throwaway test artifacts: player.html, pl.json
- Trim dead Flutter rules from .gitignore

Build from backend/Musify.slnx: 0 warnings, 0 errors.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-05 03:43:52 +02:00
co-authored by Claude Opus 4.8
parent d9c8c17b21
commit 8f34ed4874
247 changed files with 0 additions and 229 deletions
@@ -0,0 +1,63 @@
using Ardalis.Result;
using Microsoft.EntityFrameworkCore;
using Musify.Application.Configuration;
using Musify.Domain.Entities;
using Musify.Domain.ValueObjects;
using Musify.Application.Contracts;
namespace Musify.Application.Services;
public sealed class UploadIntentValidator(
IDatabase database,
IStorageService storageService)
{
public async Task<Result> CheckQuotaAsync(
UploadIntentConfiguration config,
long userId,
long requiredBytes,
int requiredIntentCount,
CancellationToken cancellationToken)
{
var activeIntents = await database.UploadIntents
.AsNoTracking()
.Where(i => i.UserId == userId && i.Status == UploadIntentStatus.Issued)
.ToListAsync(cancellationToken);
if (activeIntents.Count + requiredIntentCount > config.MaxActiveUploadIntentsPerUser)
return Result.Invalid(new ValidationError("Upload intent limit exceeded. Wait for existing uploads to complete or expire."));
var activeBytes = activeIntents.Sum(i => i.ExpectedSizeBytes ?? config.DefaultExpectedPictureSizeBytes);
if (activeBytes + requiredBytes > config.MaxActiveUploadBytesPerUser)
return Result.Invalid(new ValidationError("Upload byte quota exceeded. Wait for existing uploads to complete or expire."));
return Result.Success();
}
public async Task<Result<UploadIntent>> ValidateAndLoadAsync(
UploadIntentConfiguration config,
Guid intentId,
long userId,
CancellationToken cancellationToken)
{
var intent = await database.UploadIntents
.FirstOrDefaultAsync(i => i.Id == intentId, cancellationToken);
if (intent is null || intent.UserId != userId)
return Result.NotFound("Upload intent not found or not accessible.");
if (intent.Status == UploadIntentStatus.Consumed)
return Result.Conflict("Upload intent has already been consumed.");
if (intent.Status == UploadIntentStatus.Expired || intent.ExpiresAt < DateTime.UtcNow)
return Result.Invalid(new ValidationError("Upload intent has expired."));
var metadata = await storageService.HeadObjectAsync(intent.Bucket, intent.Key, cancellationToken);
if (metadata is null)
return Result.NotFound("Uploaded object not found in storage. Upload the file first.");
if (metadata.ContentLength > config.MaxUploadBytes)
return Result.Invalid(new ValidationError($"Uploaded file exceeds the maximum allowed size of {config.MaxUploadBytes} bytes."));
return Result.Success(intent);
}
}