feat(tickets): Volltextsuche + Kategorien, 👍/👎-Rückmeldung & ähnliche gelöste Tickets
- Suche: Volltext über Nachricht/Frage/Antwort/Changelog/Name/Kategorie, plus Kategorie-Filter (KI-gesetzte Kategorie als Chip + Auswahlmenü), je innerhalb der aktiven Ansicht. - 👍/👎 auf gelösten Tickets: 👍 speichert die Rückmeldung, 👎 öffnet das Ticket wieder (zurück in die Rückfragen) und bittet um die fehlende Info. - Melde-Fenster: schlägt beim Tippen ähnliche bereits gelöste Tickets vor (Wort-Überlappung + Bonus bei gleichem Tier/Wurf/Kontakt) — Self-Service. Backend: Feedback.Category + Feedback.Helpful (+ PUT-Handling), Migration FeedbackCategoryAndHelpful (beide nullable). Tests: 260 Backend grün, e2e Tickets Desktop +4 (Suche/Kategorie/👍/👎), vitest 149. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -47,7 +47,11 @@ namespace GerbilManagerWebAPI.Dtos
|
||||
/// <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);
|
||||
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>
|
||||
/// FEEDBACK: payload for PUT /feedback/{id}. Edit the message and/or toggle status,
|
||||
@@ -60,5 +64,9 @@ namespace GerbilManagerWebAPI.Dtos
|
||||
string? Question,
|
||||
string? Answer,
|
||||
string? FixNote,
|
||||
string? AgentContext);
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -178,6 +178,17 @@ namespace GerbilManagerWebAPI.Endpoints
|
||||
entity.AgentContext = c.Length == 0 ? null : c;
|
||||
}
|
||||
|
||||
// KATEGORIE: frei wählbares Thema für Filter/Übersicht; leer = löschen.
|
||||
if (input.Category is not null)
|
||||
{
|
||||
var cat = input.Category.Trim();
|
||||
entity.Category = cat.Length == 0 ? null : cat;
|
||||
}
|
||||
|
||||
// HILFREICH (👍/👎): nur setzen, wenn übermittelt (null = unverändert).
|
||||
if (input.Helpful is not null)
|
||||
entity.Helpful = input.Helpful;
|
||||
|
||||
await db.SaveChangesAsync();
|
||||
return TypedResults.Ok(ToDto(entity));
|
||||
});
|
||||
@@ -264,6 +275,6 @@ namespace GerbilManagerWebAPI.Endpoints
|
||||
new(f.Id, f.Message, f.Context, f.GerbilId, f.LitterId, f.ContactId, f.EntityName, f.Url,
|
||||
f.ClientTimestamp, f.UserAgent, f.CreatedAt, f.Status, f.ResolvedAt,
|
||||
f.Question, f.Answer, f.AnsweredAt, f.FixNote, f.AgentContext,
|
||||
DeserializeThread(f.Thread), f.ReopenedAt, f.DeletedAt);
|
||||
DeserializeThread(f.Thread), f.ReopenedAt, f.DeletedAt, f.Category, f.Helpful);
|
||||
}
|
||||
}
|
||||
|
||||
1800
GerbilManagerWebAPI/Migrations/20260623091325_FeedbackCategoryAndHelpful.Designer.cs
generated
Normal file
1800
GerbilManagerWebAPI/Migrations/20260623091325_FeedbackCategoryAndHelpful.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,38 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace GerbilManagerWebAPI.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class FeedbackCategoryAndHelpful : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "Category",
|
||||
table: "Feedback",
|
||||
type: "text",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<bool>(
|
||||
name: "Helpful",
|
||||
table: "Feedback",
|
||||
type: "boolean",
|
||||
nullable: true);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropColumn(
|
||||
name: "Category",
|
||||
table: "Feedback");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "Helpful",
|
||||
table: "Feedback");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -893,6 +893,9 @@ namespace GerbilManagerWebAPI.Migrations
|
||||
b.Property<DateTimeOffset?>("AnsweredAt")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<string>("Category")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<DateTimeOffset?>("ClientTimestamp")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
@@ -918,6 +921,9 @@ namespace GerbilManagerWebAPI.Migrations
|
||||
b.Property<Guid?>("GerbilId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<bool?>("Helpful")
|
||||
.HasColumnType("boolean");
|
||||
|
||||
b.Property<Guid?>("LitterId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
|
||||
@@ -70,6 +70,18 @@ namespace GerbilManagerWebAPI.Models
|
||||
/// </summary>
|
||||
public DateTimeOffset? DeletedAt { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Optionale Kategorie/Thema (von der KI gesetzt) für Filter + Übersicht, z. B.
|
||||
/// "Genetik", "Import", "Stammbaum", "Daten", "Foto". Frei wählbar (kein FK), null = ohne.
|
||||
/// </summary>
|
||||
public string? Category { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// War die Lösung hilfreich? (Daumen hoch/runter auf gelösten Tickets.) true = 👍,
|
||||
/// false = 👎 (löst i. d. R. ein Wiederöffnen aus), null = noch keine Rückmeldung.
|
||||
/// </summary>
|
||||
public bool? Helpful { get; set; }
|
||||
|
||||
/// <summary>A clarifying question (Rückfrage) a maintainer attaches to the ticket; null if none.</summary>
|
||||
public string? Question { get; set; }
|
||||
|
||||
|
||||
Reference in New Issue
Block a user