- 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>
94 lines
3.9 KiB
C#
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);
|
|
}
|