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

@@ -0,0 +1,35 @@
/** FEEDBACK: API client for the "Fehler melden" report sink (POST /feedback). */
import { api } from './client'
const RESOURCE = '/feedback'
/** Which view a report was filed from (matches the backend Context contract). */
export type FeedbackContext = 'stammbaum' | 'gerbil-detail' | 'litter-detail'
/** Payload for POST /feedback. Debug fields are captured automatically by the caller. */
export interface FeedbackInput {
message: string
context: FeedbackContext
gerbilId?: string | null
litterId?: string | null
entityName?: string | null
url?: string | null
clientTimestamp?: string | null
}
export interface Feedback {
id: string
message: string
context: string
gerbilId: string | null
litterId: string | null
entityName: string | null
url: string | null
clientTimestamp: string | null
userAgent: string | null
createdAt: string
}
export function submitFeedback(body: FeedbackInput): Promise<Feedback> {
return api.post<Feedback>(RESOURCE, body)
}