Files
GerbilManager/GerbilManagerWebAPI/Dtos/FeedbackDtos.cs
Gulum f7a1a7724b feat(tickets): Web-Push-Benachrichtigungen (PWA)
- Die Züchterin kann auf der Tickets-Seite Push-Benachrichtigungen aktivieren
  (🔔-Schalter). Service Worker ist BEWUSST push-only (kein fetch/Caching), damit das
  Laden der App nie beeinträchtigt wird.
- Backend: WebPush-Bibliothek + VAPID; PushNotifier sendet an alle Abos, räumt veraltete
  (404/410) auf. Endpoints: GET /push/vapid-public-key, POST /push/subscribe|unsubscribe.
- Ausgelöst über ein notify-Flag auf PUT /feedback: NUR die KI setzt es (z. B. neue
  Rückfrage / Ticket gelöst) → keine Selbst-Pushes durch Aktionen der Züchterin. Text wird
  aus dem Status abgeleitet, Klick öffnet das Ticket (?focus=).
- Schalter/Logik blenden sich aus, wenn das Gerät kein Push kann oder der Server keine
  VAPID-Schlüssel hat (z. B. e2e-Mock).

Migration WebPushSubscriptions. VAPID-Schlüssel in appsettings.json (lokale Single-User-App
im Heimnetz — bewusste, vertretbare Vereinfachung). Tests: 264 Backend grün (+Push-Endpoints),
e2e Tickets Desktop grün, vitest 149.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-23 11:32:26 +02:00

94 lines
3.9 KiB
C#

namespace GerbilManagerWebAPI.Dtos
{
/// <summary>FEEDBACK: payload for POST /feedback (the "Fehler melden" dialog).</summary>
public record FeedbackInput(
string Message,
string Context,
Guid? GerbilId,
Guid? LitterId,
Guid? ContactId,
string? EntityName,
string? Url,
DateTimeOffset? ClientTimestamp);
/// <summary>
/// FEEDBACK: one past Q&A turn in the ticket's thread/history.
/// Role is "maintainer" (Rückfrage) or "breeder" (Antwort).
/// </summary>
public record FeedbackThreadEntry(
string Role,
string Text,
DateTimeOffset? At);
/// <summary>FEEDBACK: lightweight metadata for an attachment (no bytes).</summary>
public record FeedbackAttachmentDto(
Guid Id,
string FileName,
string ContentType,
int Size);
/// <summary>FEEDBACK: payload to upload an attachment (base64-encoded bytes).</summary>
public record FeedbackAttachmentInput(
string FileName,
string ContentType,
string DataBase64);
/// <summary>FEEDBACK: response DTO for a stored report.</summary>
public record FeedbackDto(
Guid Id,
string Message,
string Context,
Guid? GerbilId,
Guid? LitterId,
Guid? ContactId,
string? EntityName,
string? Url,
DateTimeOffset? ClientTimestamp,
string? UserAgent,
DateTimeOffset CreatedAt,
string Status,
DateTimeOffset? ResolvedAt,
string? Question,
string? Answer,
DateTimeOffset? AnsweredAt,
/// <summary>Breeder-friendly changelog written on resolve (shown in the UI).</summary>
string? FixNote,
/// <summary>INTERNAL agent working memory — exposed for tooling, NEVER shown to the breeder.</summary>
string? AgentContext,
/// <summary>Earlier Q&A rounds, oldest first; the current open exchange stays in Question/Answer.</summary>
IReadOnlyList<FeedbackThreadEntry> Thread,
/// <summary>When a genuinely-resolved ticket (no pending Rückfrage) was reopened; else null.</summary>
DateTimeOffset? ReopenedAt = null,
/// <summary>Soft-delete marker: when the ticket was deleted via the UI (recoverable); else null.</summary>
DateTimeOffset? DeletedAt = null,
/// <summary>Optional AI-set category/topic for filtering (e.g. "Genetik", "Import"); null = none.</summary>
string? Category = null,
/// <summary>Was the resolution helpful? true=👍, false=👎, null=no feedback yet.</summary>
bool? Helpful = null,
/// <summary>Attachment metadata (no bytes); fetch bytes via /feedback/attachments/{id}.</summary>
IReadOnlyList<FeedbackAttachmentDto>? Attachments = null);
/// <summary>
/// FEEDBACK: payload for PUT /feedback/{id}. Edit the message and/or toggle status,
/// attach a clarifying question (Rückfrage), submit the breeder's answer, set the
/// breeder-friendly fix note (changelog), or update the internal agent context.
/// </summary>
public record FeedbackUpdate(
string? Message,
string? Status,
string? Question,
string? Answer,
string? FixNote,
string? AgentContext,
/// <summary>Set/clear the ticket category. Empty/whitespace clears it.</summary>
string? Category = null,
/// <summary>👍/👎 on a resolved ticket. null leaves it unchanged.</summary>
bool? Helpful = null,
/// <summary>
/// Wenn true, wird nach dem Update eine Push-Benachrichtigung an die Züchterin gesendet.
/// Nur die KI/der Betreuer setzt das (z. B. neue Rückfrage / Ticket gelöst); das Frontend
/// setzt es NIE — so löst die Züchterin mit eigenen Aktionen keine Selbst-Pushes aus.
/// </summary>
bool? Notify = null);
}