feat(bug-reports): Herkunft der Fehlermeldung im Betreff-Kuerzel und als Zeile Herkunft ausweisen

WebView2 (Windows) sieht im User-Agent aus wie Edge, WebKitGTK (Linux) wie
Safari — im Postfach war eine Client-Meldung von einer Browser-Meldung
nicht zu unterscheiden. Neuer reiner Helfer origin.ts leitet aus vier
optionalen DTO-Feldern (Desktop-App) bzw. dem User-Agent (Browser) ein
Betreff-Kuerzel und eine Zeile "Herkunft: ..." ab; rein informativ,
laengenbegrenzt, nichts wird gespeichert (T-GZA-01). Browser-Pfad ist
damit Ende-zu-Ende fertig.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016g2npLxzH5gZpg8s2S6vKh
This commit is contained in:
2026-09-18 12:32:29 +02:00
parent ab99a9ab5d
commit 716947228e
6 changed files with 411 additions and 6 deletions
@@ -14,6 +14,7 @@ import { forTenant } from '../prisma/prisma-tenant.extension';
import { PrismaService } from '../prisma/prisma.service';
import { SettingsService } from '../settings/settings.service';
import { BugReportDto } from './dto/bug-report.dto';
import { describeOrigin } from './origin';
/**
* BugReportsService — Fehler-melden-Knopf (quick-260914-m97).
@@ -43,6 +44,14 @@ import { BugReportDto } from './dto/bug-report.dto';
* Benutzer ausschliesslich aus dem Sitzungsnachweis, Benutzerzeile ueber
* einen gebundenen Klienten — Zeile in
* docs/mandantentrennung-zugriffsklassifikation.md).
*
* Herkunft (quick-260918-gza): der Betreff traegt seit dieser Aenderung
* ein Kuerzel (`[Browser]`, `[Desktop/Windows]`, `[Desktop/Linux]`, oder
* `[Desktop]` bei einem alten Client ohne Details), damit sich das
* Postfach danach sortieren laesst — WebView2 sieht sonst aus wie Edge,
* WebKitGTK wie Safari. Der rohe User-Agent bleibt in der Zeile
* `Browser:` unveraendert erhalten, die Ableitung selbst steht in
* `origin.ts` (dort auch T-GZA-01: rein informativ, laengenbegrenzt).
*/
const WINDOW_MS = 10 * 60 * 1000;
@@ -119,9 +128,10 @@ export class BugReportsService {
const email: string = row?.email ?? '-';
const role: string = row?.role ?? user.role;
// (5) Betreff
// (5) Betreff — Herkunfts-Kuerzel direkt nach dem festen Praefix (quick-260918-gza).
const origin = describeOrigin(dto);
const pageShort = dto.page.slice(0, 120);
const subject = `[Tessera Fehlermeldung] ${dto.webVersion} ${dto.webChannel} - ${pageShort}`;
const subject = `[Tessera Fehlermeldung] ${origin.tag} ${dto.webVersion} ${dto.webChannel} - ${pageShort}`;
// (6) Text
const bytes = file ? file.buffer.length : 0;
@@ -139,6 +149,7 @@ export class BugReportsService {
`Mandant: ${user.tenantId}`,
`Web: ${dto.webVersion} (${dto.webChannel}) ${dto.webCommit}`.trimEnd(),
`API: ${formatAppVersionLine()}`,
`Herkunft: ${origin.line}`,
`Browser: ${dto.userAgent}`,
`Fenster: ${dto.viewport}`,
'',
@@ -164,8 +175,10 @@ export class BugReportsService {
}
// (9) Genau eine Protokollzeile — nie Beschreibung, nie Bild (T-M97-07).
// Das Kuerzel ist ein aufgezaehlter Wert aus origin.ts, nie ein roher
// Client-String — deshalb protokollierbar (T-GZA-01).
this.logger.log(
`Bug report from ${user.username} (tenant ${user.tenantId}) sent to ${to} — page ${pageShort}, screenshot ${bytes} bytes`,
`Bug report ${origin.tag} from ${user.username} (tenant ${user.tenantId}) sent to ${to} — page ${pageShort}, screenshot ${bytes} bytes`,
);
return { sent: true };
}