Files
GerbilManager/GerbilManagerWebAPI/Dtos/ApiDtos.cs
Gulum 54e873c115
All checks were successful
CI / Backend Tests (.NET) (push) Successful in 1m15s
CI / Frontend Tests (Node/Vite) (push) Successful in 9m37s
CI / Docker Build & Push (push) Successful in 7m36s
CI / Deploy auf TrueNAS (Custom App) (push) Successful in 8s
feat(tiere): Eltern direkt in der Tier-Akte bearbeiten (QOL)
Im Tier-Formular gibt es jetzt den Block „Abstammung" mit Wurf-Auswahl und
Vater-/Mutter-Picker — die Eltern müssen nicht mehr über die Wurf-Seite
gesucht und dort editiert werden. Das Datenmodell bleibt unverändert: Eltern
hängen weiterhin am Geburtswurf.

- Backend: PUT /gerbils/{id}/parents schreibt Litter.FatherId/MotherId des
  Geburtswurfs. Ohne Wurf wird ein bestehender mit gleichem Elternpaar +
  gleichem Datum verknüpft, sonst ein Träger-Wurf angelegt
  ("Wurf von X + Y", ShowInChronicle=false, IsManual=true).
  Geschlechts-Regel wiederverwendet LitterEndpoints.ValidateParents,
  Selbstbezug (Tier als eigener Elternteil) wird abgewiesen.
- UI: Vorbelegung aus dem gewählten Wurf, Warnung mit Anzahl der Geschwister
  (Eltern gehören dem Wurf → Änderung gilt für alle), Hinweis wenn ein
  Wurf-Eintrag angelegt wird. Texte in de.ts.
- Nebenbei: Speichern nutzt im Edit-Modus die Route-Id (PUT /gerbils/{id}
  antwortet 204 ohne Body) und der vorher schon rote Spec-Locator
  „Würfe als Elternteil" ist auf den Abschnitt eingegrenzt.
- Tests: GerbilParentsTests (9), e2e tiere.spec (2 neu) + Mock-Route.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-19 20:43:28 +02:00

163 lines
6.2 KiB
C#

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? SpottingType,
string? Notes,
string? ImportSource,
string? ExternalRef,
string? OriginBreeder,
List<string> CharacterTraits,
string? CharacterNote,
bool? IsDeaf,
bool IsResident,
string? ProfilePhotoUrl,
bool IsCastrated,
string? Provenance,
int? BirthOrder = null);
public record LitterDto(
Guid Id,
string Name,
DateOnly? Date,
int? TotalBorn,
int? DeathsWithin8Weeks,
int? Stillborn,
Guid? FatherId,
Guid? MotherId,
DateOnly? ExpectedGoHomeDate,
string? Notes,
string? Provenance,
bool ShowInChronicle);
public record ContactDto(Guid Id, string Name, string? Email, string? Phone, string? Address, string? Notes, bool IsBreeder, bool IsReceiver, string? NameSuffix, string? Provenance);
public record EnclosureDto(
Guid Id, string Name, string? Notes,
string? Size, int? Capacity,
DateOnly? LastCleanedDate, int? CleaningCycleDays, DateOnly? NextCleaningDate);
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);
// VERIFIED/PROTECTED OVERRIDE -------------------------------------------
// Status: "unchanged" = raw import agrees with the golden state; "drifted" = the raw import
// differs from the golden state (see ImportDiff — a signal for what the importer might still
// get wrong); "missing" = the verified animal no longer exists in the imported data.
public record VerifiedGerbilDto(
Guid GerbilId,
string? EntityName,
bool IsVerified,
string Status,
DateTimeOffset? VerifiedAt,
DateTimeOffset UpdatedAt,
string? Note,
IReadOnlyList<string> ProtectedFields,
IReadOnlyList<SnapshotDiffDto> ImportDiff);
/// <summary>One field difference between the golden state and the raw import.</summary>
public record SnapshotDiffDto(string Path, string? GoldenValue, string? ImportValue);
/// <summary>Export entry for the committed regression fixture (verified-golden.json).</summary>
public record VerifiedGoldenEntry(
Guid GerbilId, string? Name, DateTimeOffset? VerifiedAt, Import.GerbilSnapshot? Snapshot);
// Request DTOs -----------------------------------------------------------
/// <summary>Body for POST /verified-gerbils/{id} — optional free-text note.</summary>
public record VerifyGerbilInput(string? Note);
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? SpottingType,
string? Notes,
string? ImportSource,
string? ExternalRef,
string? OriginBreeder,
List<string>? CharacterTraits,
string? CharacterNote,
bool? IsDeaf,
bool? IsResident,
bool? IsCastrated);
/// <summary>QOL: Eltern direkt in der Tier-Akte setzen (PUT /gerbils/{id}/parents).
/// Das Datenmodell bleibt unverändert — geschrieben werden die Eltern des GEBURTSWURFS.</summary>
public record GerbilParentsInput(Guid? FatherId, Guid? MotherId);
/// <summary>Ergebnis von PUT /gerbils/{id}/parents: welcher Wurf die Eltern jetzt trägt, ob er
/// dafür neu angelegt (LitterCreated) bzw. ein bestehender verknüpft wurde (LitterAttached) und
/// wie viele Geschwister im selben Wurf die Änderung mitbetrifft.</summary>
public record GerbilParentsResult(
Guid? LitterId, string? LitterName, bool LitterCreated, bool LitterAttached,
int SiblingCount, Guid? FatherId, Guid? MotherId);
public record LitterInput(
string Name,
DateOnly? Date,
int? TotalBorn,
int? DeathsWithin8Weeks,
int? Stillborn,
Guid? FatherId,
Guid? MotherId,
DateOnly? ExpectedGoHomeDate,
string? Notes,
bool? ShowInChronicle = null);
public record ContactInput(string Name, string? Email, string? Phone, string? Address, string? Notes, bool IsBreeder, bool IsReceiver, string? NameSuffix);
public record EnclosureInput(
string Name, string? Notes,
string? Size, int? Capacity,
DateOnly? LastCleanedDate, int? CleaningCycleDays);
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);
}