feat(feedback): Fehler-melden-Dialog + ID-kopieren (Stammbaum/Akte/Wurf)

Rechtsklick auf eine Maus im Stammbaum öffnet ein Kontextmenü mit „ID kopieren"
(Clipboard + Toast) und „Fehler melden". Zusätzlich „Fehler melden"-Buttons in
der Rennmausakte und der Wurf-Ansicht. Der Dialog erfasst eine Beschreibung und
sendet sie samt Debug-Kontext (Ansicht, Tier-/Wurf-ID + Name, URL, Zeitstempel,
User-Agent) an POST /feedback; gespeichert in einer neuen Feedback-Tabelle.

Backend: Feedback-Entity (lose nullable GerbilId/LitterId ohne FK), Endpoints
POST/GET /feedback, EF-Migration AddFeedback. Die Tabelle wird vom Import-Ingest
NICHT geleert — Feedback überlebt Re-Ingests (Test deckt das ab).

Tests: FeedbackEndpointTests (persistiert, 400 bei leer, übersteht Ingest-Wipe);
e2e feedback.spec.ts. tsc/eslint/vitest(129)/playwright(6)/dotnet(212) grün.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-22 15:30:42 +02:00
parent 1845d37476
commit b9e5b031c4
20 changed files with 2586 additions and 2 deletions

View File

@@ -793,6 +793,48 @@ namespace GerbilManagerWebAPI.Migrations
b.ToTable("EnclosurePhotos");
});
modelBuilder.Entity("GerbilManagerWebAPI.Models.Feedback", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<DateTimeOffset?>("ClientTimestamp")
.HasColumnType("timestamp with time zone");
b.Property<string>("Context")
.IsRequired()
.HasColumnType("text");
b.Property<DateTimeOffset>("CreatedAt")
.HasColumnType("timestamp with time zone");
b.Property<string>("EntityName")
.HasColumnType("text");
b.Property<Guid?>("GerbilId")
.HasColumnType("uuid");
b.Property<Guid?>("LitterId")
.HasColumnType("uuid");
b.Property<string>("Message")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Url")
.HasColumnType("text");
b.Property<string>("UserAgent")
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("CreatedAt");
b.ToTable("Feedback");
});
modelBuilder.Entity("GerbilManagerWebAPI.Models.Gerbil", b =>
{
b.Property<Guid>("Id")