DATA-2: new schema entities + Minimal API endpoints + Scalar + DAL teardown

- Entities: Breeder->Contact, +Enclosure/ColorVariety/GerbilPhoto/HealthRecord/WeightRecord;
  Gerbil expanded (single Genotype text col, Status/Gender enums-as-string, FK ids,
  ImportSource/ExternalRef provenance); Litter Strength->TotalBorn +ExpectedGoHomeDate/Notes.
  ColorVariety HasData seed = 18 from GEN-1 catalog. Gerbil<->Litter cycle handled
  (SetNull/Restrict). Enums stored as strings.
- Minimal API (no controllers): Endpoints/*.cs MapGroup+TypedResults for gerbils, litters,
  contacts, enclosures, color-varieties, health/weight-records, inbreeding (converted from
  controller, same routes/shapes), photos (Oscar contract: GET array/POST multipart/DELETE,
  url /photos/files/{fileName}). Gridify paged {items,totalCount,page,pageSize}, camelCase,
  409 conflict-deletes, flat FK ids, litter parent-gender validation (400 {code,...}).
- Scalar replaces Swashbuckle (AddOpenApi/MapOpenApi + MapScalarApiReference at /scalar);
  launchUrl swagger->scalar. GenericRepository/UnitOfWork/Converters deleted; DbContext direct.
- InbreedingService reads real FK props now; pure calculator + 8 tests untouched.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-06 00:53:49 +02:00
parent a47fbef785
commit 180d53b203
46 changed files with 1070 additions and 750 deletions

View File

@@ -0,0 +1,96 @@
using GerbilManagerWebAPI.Models;
namespace GerbilManagerWebAPI.Dtos
{
// Response DTOs ----------------------------------------------------------
// Enums serialise as string names; JSON property names are camelCase (configured
// globally in Program.cs). FK references are FLAT ids (no nested objects) per the
// frontend contract (Kelly's pedigree + Oscar's filters depend on this).
public record GerbilDto(
Guid Id,
string Name,
Gender Gender,
GerbilStatus Status,
Guid? LitterId,
Guid? OriginContactId,
Guid? ReceiverContactId,
Guid? EnclosureId,
Guid? ColorVarietyId,
DateOnly? DateOfBirth,
DateOnly? DateOfDeath,
string? CauseOfDeath,
DateOnly? GoHomeDate,
string? Genotype,
string? Notes,
string? ImportSource,
string? ExternalRef);
public record LitterDto(
Guid Id,
string Name,
DateOnly Date,
int? TotalBorn,
Guid? FatherId,
Guid? MotherId,
DateOnly? ExpectedGoHomeDate,
string? Notes);
public record ContactDto(Guid Id, string Name, string? ContactInfo, string? Notes);
public record EnclosureDto(Guid Id, string Name, string? Notes);
public record ColorVarietyDto(Guid Id, string Name, string? CanonicalGenotype, int SortOrder);
public record HealthRecordDto(
Guid Id, Guid GerbilId, DateOnly Date, HealthRecordType Type,
string Description, string? Veterinarian, DateTimeOffset CreatedAt);
public record WeightRecordDto(
Guid Id, Guid GerbilId, DateOnly Date, int WeightGrams, string? Notes);
public record PhotoDto(Guid Id, string FileName, string? Caption, int SortOrder, string Url);
// Request DTOs -----------------------------------------------------------
public record GerbilInput(
string Name,
Gender Gender,
GerbilStatus? Status,
Guid? LitterId,
Guid? OriginContactId,
Guid? ReceiverContactId,
Guid? EnclosureId,
Guid? ColorVarietyId,
DateOnly? DateOfBirth,
DateOnly? DateOfDeath,
string? CauseOfDeath,
DateOnly? GoHomeDate,
string? Genotype,
string? Notes,
string? ImportSource,
string? ExternalRef);
public record LitterInput(
string Name,
DateOnly Date,
int? TotalBorn,
Guid? FatherId,
Guid? MotherId,
DateOnly? ExpectedGoHomeDate,
string? Notes);
public record ContactInput(string Name, string? ContactInfo, string? Notes);
public record EnclosureInput(string Name, string? Notes);
public record ColorVarietyInput(string Name, string? CanonicalGenotype, int? SortOrder);
public record HealthRecordInput(
Guid GerbilId, DateOnly Date, HealthRecordType Type, string Description, string? Veterinarian);
public record WeightRecordInput(Guid GerbilId, DateOnly Date, int WeightGrams, string? Notes);
/// <summary>Hypothetical pairing request for POST /genetics/test-inbreeding.</summary>
public record TestInbreedingDto(Guid? FatherId, Guid? MotherId);
}

View File

@@ -1,8 +0,0 @@
namespace GerbilManagerWebAPI.Dtos
{
public record BreederDto
{
public Guid Id { get; init; }
public required string Name { get; init; }
}
}

View File

@@ -1,7 +0,0 @@
namespace GerbilManagerWebAPI.Dtos
{
public record CreateBreederDto
{
public required string Name { get; init; }
}
}

View File

@@ -1,11 +0,0 @@
namespace GerbilManagerWebAPI.Dtos
{
public record CreateGerbilDto
{
public required string Name { get; init; }
public required GenderDto Gender { get; init; }
public Guid Litter { get; init; }
public Guid Breeder { get; init; }
}
}

View File

@@ -1,11 +0,0 @@
namespace GerbilManagerWebAPI.Dtos
{
public record CreateLitterDto
{
public required string Name { get; init; }
public required DateTime Date { get; init; }
public int? Strength { get; init; }
public Guid? Father { get; init; }
public Guid? Mother { get; init; }
}
}

View File

@@ -1,9 +0,0 @@
namespace GerbilManagerWebAPI.Dtos
{
public enum GenderDto
{
unknown = 0,
male = 1,
female = 2
}
}

View File

@@ -1,11 +0,0 @@
namespace GerbilManagerWebAPI.Dtos
{
public record GerbilDto
{
public Guid Id { get; init; }
public required string Name { get; init; }
public required GenderDto Gender { get; init; }
public LitterDto? Litter { get; init; }
public BreederDto? Breeder { get; init; }
}
}

View File

@@ -1,12 +0,0 @@
namespace GerbilManagerWebAPI.Dtos
{
public record LitterDto
{
public Guid Id { get; init; }
public required string Name { get; init; }
public required DateTime Date { get; init; }
public int? Strength { get; init; }
public GerbilDto? Father { get; init; }
public GerbilDto? Mother { get; init; }
}
}

View File

@@ -1,9 +0,0 @@
namespace GerbilManagerWebAPI.Dtos
{
/// <summary>
/// Request body for a hypothetical pairing's inbreeding coefficient
/// (Inzuchtkoeffizient der geplanten Verpaarung). Either parent may be omitted,
/// in which case the coefficient is 0.
/// </summary>
public record TestInbreedingDto(Guid? FatherId, Guid? MotherId);
}

View File

@@ -1,8 +0,0 @@
namespace GerbilManagerWebAPI.Dtos
{
public record UpdateBreederDto
{
public string? Name { get; init; }
}
}

View File

@@ -1,10 +0,0 @@
namespace GerbilManagerWebAPI.Dtos
{
public record UpdateGerbilDto
{
public string? Name { get; init; }
public GenderDto? Gender { get; init; }
public Guid? Litter { get; init; }
public Guid? Breeder { get; init; }
}
}

View File

@@ -1,12 +0,0 @@
namespace GerbilManagerWebAPI.Dtos
{
public record UpdateLitterDto
{
public string? Name { get; init; }
public DateTime? Date { get; init; }
public int? Strength { get; init; }
public Guid? Father { get; init; }
public Guid? Mother { get; init; }
}
}