Zum Hauptinhalt springen

Feedback-Modul

Zweck

Das Feedback-Modul ermöglicht es Anwendern, Bugs, Feature-Wünsche und Verbesserungsvorschläge strukturiert zu melden — mit Screenshot, mehreren Bild-Anhängen, markiertem UI-Element und Vorgangs-Aufzeichnung. Im Standard sehen Anwender nur ihre eigenen Meldungen; Admins mit do:ViewAllFeedback sehen alle.

Das Tool ist als kleiner Feedback-Button im App-Footer unten rechts immer sichtbar. Klick öffnet ein Drawer, das den User durch Kategorie/Titel/Beschreibung/Priorität/Screenshot/Anhänge/Recording führt. Drafts werden lokal gespeichert und überleben das Schließen des Drawers.

Operative Anleitung: Feedback melden — Bugs, Features, Verbesserungsvorschläge.

Voraussetzungen

- Mandant mit aktiviertem Feedback-System. - User mit Berechtigung `view:FE_Feedback` + `view:Feedback` (typisch alle Anwender). - Für Admin-Sicht zusätzlich `do:ViewAllFeedback`.

Berechtigungen (CASL)

Frontend-Page-Guard (/feedback):

ActionSubjectWirkung
viewFE_FeedbackModul-Route aufrufbar
viewFeedbackListe sichtbar

API-Datenzugriff:

ActionSubjectWirkung
viewFeedbackeigene Feedbacks lesen
createFeedbackneue Meldung anlegen
updateFeedbackMeldung bearbeiten (Status/Priorität — typisch nur Admin)
deleteFeedbacklöschen (Soft-Delete)
doViewAllFeedbackalle Feedbacks aller User sehen (Power-Permission, typisch nur IT/Kevin)

Sichtbarkeits-Logik (BE): Ohne do:ViewAllFeedback filtert die API automatisch auf reportedBy === currentEmployeeId. Implementierung in api.speamcore.com/src/services/feedback.service.ts.

Datenmodell

FeldTypBedeutung
idUUIDPrimary Key
sequenceIdNumberfortlaufend pro Mandant
typeenumbug | feature_request | improvement
statusenumopen | in_review | planned | in_progress | done | rejected | forwarded (Default: open)
priorityenum nullablelow | medium | high | critical (primär für Bugs)
titleString, max. 255Kurz-Titel
descriptionText, nullableausführliche Beschreibung
developerStatusNoteText nullableAntwort/Notiz des Entwickler-Teams — nur dieses darf schreiben (read-only für den Melder).
developerStatusUpdatedAtDateTime nullablewann die Entwickler-Notiz zuletzt geändert wurde.
masterIdUUID nullableVerweis auf die Admin-Master-Row. Wird beim Reporter direkt nach dem Anlegen vorgestempelt (eigene id) und nach dem Push/Sync gesetzt — daran erkennt das System die gespiegelte Cross-Mandanten-Kopie.
originTenantIdUUID nullablenur auf dem Entwickler-Mirror gefüllt: ID des Reporter-Mandanten (woher das Feedback kam). Auf der Reporter-eigenen Row null.
originTenantNameString nullableSnapshot des Reporter-Mandantennamens für die Anzeige beim Entwickler.
screenshotDocumentIdUUID nullableFK → Document mit dem Screenshot
targetSelectorString nullableCSS-Selector / DOM-Pfad des markierten Elements
routeString nullableURL-Pfad zur Zeit der Meldung
metadataJSON nullableBrowser, OS, Viewport, App/API-Version, Bounding-Box des Elements
reportedByUUIDEmployee.id (auto aus Token)
createdAt, updatedAt, deletedAtDateTimeStandard-Zeitstempel + Soft-Delete

Status-Workflow + Entwickler-Antwort (seit Juni 2026)

Das Feedback durchläuft die Stufen open → in_review → planned → in_progress → done (oder rejected). Zusätzlich gibt es forwarded: Der Admin leitet das Feedback automatisch an den Entwickler-Mandanten (reporter.primaryTenantId) weiter; dort wird es per Standard-Sync gezogen und beim Annehmen auf in_progress gesetzt. Das Entwickler-Team kann eine Antwort/Notiz hinterlegen (developerStatusNote), die beim Melder read-only angezeigt wird — so sieht der Melder den Bearbeitungsstand und die Rückmeldung der Entwickler.

Cross-Mandanten-Spiegelung (Reporter ↔ Entwickler)

Technisch läuft die Weiterleitung als bidirektionale Spiegelung über die drei Felder masterId, originTenantId und originTenantName:

  1. Reporter-Seite: Beim Anlegen stempelt ein afterCreate-Hook masterId vor und schiebt die Meldung (samt Screenshot) zum Admin. Dort entsteht die Master-Row.
  2. Entwickler-Seite: Der Admin zieht die Master-Row in den Entwickler-Mandanten und setzt dabei originTenantId + originTenantName — der Entwickler sieht also, von welchem Mandanten die Meldung stammt. Auf diesem Mirror darf der Entwickler nur status, priority, developerStatusNote und developerStatusUpdatedAt ändern; der Rest (Reporter-Inhalt) ist read-only.
  3. Rückweg: Änderungen an Status/Notiz werden automatisch zurück zum Admin und von dort zur Reporter-Row synchronisiert — der Melder sieht die Entwickler-Antwort read-only.

Module-Architektur

Screenshot-Strategie (dreistufige Fallback-Kette)

Beim Klick auf Screenshot aufnehmen läuft eine dreistufige Strategie, die je nach Plattform den qualitativ besten Pfad wählt:

StufePlattformTechnikErgebnis
1iOS-/Android-App (Capacitor)WKWebView.takeSnapshot() bzw. View.draw(Canvas) (Native Plugin)Echtes Compositor-Bild, keine Permission-Prompts
2Desktop-Browsernavigator.mediaDevices.getDisplayMedia()Pixel-genauer Compositor-Output, Browser zeigt Tab-Picker
3Fallback (alte Browser, blockierte Stufe 2)html2canvas mit 3-2-1-CountdownDOM-Clone, kann bei backdrop-filter/oklch/Custom-Fonts Artefakte zeigen

Stufen 1 und 2 erkennt der Code per Feature-Detection (Capacitor.isNativePlatform() und navigator.mediaDevices?.getDisplayMedia). Der Drawer wird beim Native-Capture 80 ms vor dem Snapshot ausgeblendet; bei html2canvas werden [data-feedback-ui="true"]-Elemente per ignoreElements ausgespart.

Custom-Bild-Anhänge

Zusätzlich zum Screenshot kann der User beliebig viele weitere Bilder über den Button „Bild hinzufügen" an die Meldung hängen:

  • File-Picker mit accept="image/*" und multiple — also Mehrfach-Auswahl in einem Schritt.
  • Jeder Anhang erhält UUID, Blob, Dateiname und eine Preview-URL (URL.createObjectURL).
  • Thumbnail-Galerie 96 × 96 px mit Remove-Button pro Anhang.
  • Upload-Verhalten: Anhänge werden nach der erfolgreichen Feedback-Erstellung parallel hochgeladen (POST /api/documents mit parentType="Feedback", parentId=<feedbackId>, documentType="image"). Schlägt ein einzelner Upload fehl, wird das per Warn-Log dokumentiert — das Feedback selbst bleibt gültig.
  • Im Detail-Modal lädt die Sicht die Anhänge per listDocuments(parentType=Feedback, parentId=...) und dedupliziert sie gegen screenshotDocumentId.

Draft-Persistenz

Solange der User das Drawer nicht absichtlich verwirft, bleibt die Meldung lokal erhalten:

  • Storage-Key: speamcore.feedback.draft.v1 (localStorage)
  • Persistierte Felder: type, title, description, priority, picked (markiertes Element), savedAt
  • Nicht persistiert: screenshotBlob und attachments (Blob-Größen würden das localStorage-Quota sprengen)
  • Auto-Save: bei jeder Änderung der persistierten Felder, sofern Inhalt vorhanden
  • TTL: 7 Tage — ältere Drafts werden beim nächsten Öffnen verworfen
  • Cleanup: Drawer schließen → Draft bleibt; Verwerfen-Button und erfolgreicher Submit → Draft gelöscht; Confirm-Dialog beim Verwerfen, falls Inhalt vorhanden

Recording (Vorgangs-Aufzeichnung)

Die Vorgangs-Aufzeichnung erfasst die User-Interaktion in der App — keine Bildschirm-Aufnahme, sondern eine strukturierte Click-Sequenz:

  • Listener auf pointerdown (capture phase) — fängt Klicks früher als click und erkennt auch synthetische Events.
  • Element-Resolve via closest(INTERACTIVE_SELECTOR) (Buttons, Links, Inputs, ARIA-Rollen) — leere Container-Klicks werden gefiltert.
  • Feedback-UI ist explizit ausgeschlossen über data-feedback-ui="true".
  • De-duping: doppelte Klicks innerhalb von 250 ms auf das gleiche Target werden zusammengefasst.
  • Pro Schritt erfasst: id, timestamp (ISO), url (Pfad + Query), selector (via @medv/finder), tagName, innerText (gekürzt auf 200 Zeichen), Bounding-Box.

Verwandte Doku

Versionshinweise

  • 2026-06-11: Cross-Mandanten-Spiegelung dokumentiert — neue Felder masterId, originTenantId, originTenantName und die bidirektionale Reporter ↔ Entwickler-Synchronisation (Pre-Stamp beim Reporter, Entwickler-Mirror mit Herkunfts-Snapshot, Rückweg der Status-/Notiz-Änderungen). Verifiziert an feedback.model.ts (after-Hooks, Field-Lock) und Feedback.ts (Client-Modell).
  • 2026-06-09: Status forwarded (Weiterleitung an Entwickler-Mandant) + Entwickler-Antwort (developerStatusNote/developerStatusUpdatedAt, nur Entwickler schreibt) dokumentiert; Status-Workflow ergänzt. Verifiziert an feedback.model.ts.
  • 2026-05 (Welle 96): Initiale Doku basiert auf Code-Stand der master-Branches speamcore.com (Tag v1.71.0) und api.speamcore.com (Tag v1.64.0). BE-Tasks-Folder: tasks/2026-04-29_feedback-system/ mit DECISIONS, PROGRESS, NEXT_STEPS.
  • 2026-05-12 (Welle 114): Dreistufige Screenshot-Strategie (Capacitor-Native → getDisplayMediahtml2canvas), Custom-Bild-Anhänge als separate Documents (parentType=Feedback), Draft-Persistenz in localStorage (speamcore.feedback.draft.v1, 7-Tage-TTL), verbessertes Recording via pointerdown + closest(INTERACTIVE_SELECTOR) + Feedback-UI-Ausschluss + 250 ms De-duping.