Unter Hilfe (/hilfe/tickets) eine Verwaltung der eingereichten „Fehler melden"-
Berichte: Liste (neueste zuerst) mit Status-Badge (Offen / ✓ Gelöst), Kontext-
Label, betroffenem Objekt, Nachricht und Datum. Pro Ticket: als gelöst markieren/
wieder öffnen, Nachricht inline bearbeiten, löschen (mit Bestätigung).
Backend: Feedback um Status ("Open"/"Resolved", Default Open) + nullable ResolvedAt
erweitert (weiterhin FK-frei → übersteht Ingest-Wipe); Migration AddFeedbackStatus.
Endpoints: GET /feedback (neueste zuerst, inkl. Status), PUT /feedback/{id}
(Nachricht/Status; leer→400, fehlt→404; lösen setzt/öffnen löscht ResolvedAt),
DELETE /feedback/{id} (fehlt→404).
Tests: FeedbackEndpointTests (CRUD + Status-Lebenszyklus + übersteht Ingest),
e2e tickets.spec.ts; dotnet 215, vitest 129, playwright grün.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
57 lines
2.4 KiB
C#
57 lines
2.4 KiB
C#
using System.ComponentModel.DataAnnotations;
|
|
|
|
namespace GerbilManagerWebAPI.Models
|
|
{
|
|
/// <summary>
|
|
/// FEEDBACK: a user-submitted "Fehler melden" report. Decoupled from the rest of the
|
|
/// model on purpose — GerbilId/LitterId are plain nullable Guid columns (NOT enforced
|
|
/// foreign keys), so the import re-ingest wipe (IngestResolvedService) can delete
|
|
/// gerbils/litters without deleting or breaking feedback rows. The captured EntityName
|
|
/// keeps the report human-readable even after the referenced animal is gone.
|
|
/// </summary>
|
|
public class Feedback
|
|
{
|
|
[Key]
|
|
public Guid Id { get; set; }
|
|
|
|
/// <summary>The user's free-text description of the problem.</summary>
|
|
public required string Message { get; set; }
|
|
|
|
/// <summary>Which view the report came from: stammbaum | gerbil-detail | litter-detail.</summary>
|
|
public required string Context { get; set; }
|
|
|
|
/// <summary>Loose reference (no FK) to the gerbil the report is about, if any.</summary>
|
|
public Guid? GerbilId { get; set; }
|
|
|
|
/// <summary>Loose reference (no FK) to the litter the report is about, if any.</summary>
|
|
public Guid? LitterId { get; set; }
|
|
|
|
/// <summary>Loose reference (no FK) to the contact the report is about, if any.</summary>
|
|
public Guid? ContactId { get; set; }
|
|
|
|
/// <summary>Captured name of the referenced animal/litter (survives an ingest wipe).</summary>
|
|
public string? EntityName { get; set; }
|
|
|
|
/// <summary>The client URL/route the report was filed from.</summary>
|
|
public string? Url { get; set; }
|
|
|
|
/// <summary>Client-supplied timestamp (when the user submitted, in their browser).</summary>
|
|
public DateTimeOffset? ClientTimestamp { get; set; }
|
|
|
|
/// <summary>Optional browser user-agent for diagnostics.</summary>
|
|
public string? UserAgent { get; set; }
|
|
|
|
/// <summary>Server-side creation time.</summary>
|
|
public DateTimeOffset CreatedAt { get; set; }
|
|
|
|
/// <summary>
|
|
/// Ticket lifecycle status: "Open" | "Resolved" (default "Open"). Plain string,
|
|
/// no FK — keeps feedback decoupled and ingest-surviving like the rest of the row.
|
|
/// </summary>
|
|
public string Status { get; set; } = "Open";
|
|
|
|
/// <summary>When the ticket was marked resolved; null while open.</summary>
|
|
public DateTimeOffset? ResolvedAt { get; set; }
|
|
}
|
|
}
|