Intégrer widget feedback (Feedback Hub) #67
Labels
No labels
source:analyste
source:defenseur
source:human
source:medic
status:approved
status:blocked
status:in-progress
status:needs-fix
status:ready
status:review
status:triage
type:bug
type:feature
type:infra
type:refactor
type:schema
type:security
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference: maximus/Simpl-Resultat#67
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Contexte
Intégrer le widget Feedback Hub dans Simpl'Résultat (desktop Tauri v2). Le service
feedback-apiest déployé àhttps://feedback.lacompagniemaximus.com.Documents de référence
la-compagnie-maximus/docs/feedback-hub-ops.md— source de vérité opérationnelle (contrat API, conventions wording, placement, registre des apps)la-compagnie-maximus/spec-feedback-hub.md— spec d'origine (design, figé)la-suite-booking/components/feedback/FeedbackWidget.tsx— référence d'implémentation clientIssues liées
maximus/simpl-liste#68 — version mobile, non bloquant mais à garder en cohérencela-compagnie-maximuspour MAJ du registre post-intégrationTension privacy-first
L'app est explicitement "privacy-first, zéro donnée envoyée vers un serveur tiers". CSP actuelle (
src-tauri/tauri.conf.json) n'autorise queapi.etauth.lacompagniemaximus.com. L'intégration :docs.*Décision de design
Emplacement (déviation assumée des conventions cross-app) :
FAB bas-droit(site vitrine) ouicône topbar(booking)LogViewerCard. Pas de FAB, pas d'icône persistante dans le chrome. Justifié par l'esthétique minimaliste + les logs déjà disponibles au même endroit pour le diagnostic.feedback-hub-ops.mdpost-intégration.Transport : proxy via Rust (commande Tauri
send_feedback) :FEEDBACK_CORS_ORIGINSet on évite de l'ajouter)startOAuth,validateLicenseKey, updater (pattern existant)Flow utilisateur :
LogViewerCard.tsx)page,locale,theme,viewport,timestamp+userAgentcomposé ("Simpl'Résultat/<version> (<os>)")content(pas aucontext— volontaire, limite 2000 char)useAuth().state.status === "authenticated") → envoie l'identifiant Maximus dansuser_idfeedbackConsentAcceptedpersisté (localStorage ou config profile).Payload conforme au contrat API
Le serveur a une whitelist stricte
ALLOWED_CONTEXT_KEYS = {page, locale, theme, viewport, userAgent, referrer, timestamp}(clés non-whitelistées silencieusement droppées, 500 chars/champ). Aucune extension de la whitelist n'est souhaitée (convention cross-app).Exemple envoi (toutes checkboxes cochées)
app_version+os→ packés dansuserAgent, pas de clés customprofile_name→ pas envoyé (local-only, pas de sens cross-app)logs→ suffixe ducontentavec séparateur\n\n---\nLogs récents :\n, troncature pour rester sous 2000 char totaluser_id: identifiant Maximus depuisuseAuth().state.account(à confirmer côté impl :idouemailselon ce que retournegetAccountInfo())Wording (conforme au guide ops pour cohérence cross-app)
feedback.buttonfeedback.dialog.titlefeedback.dialog.placeholderfeedback.dialog.submitfeedback.dialog.cancelfeedback.checkbox.contextfeedback.checkbox.logsfeedback.checkbox.identifyfeedback.toast.successfeedback.toast.error.429feedback.toast.error.400feedback.toast.error.genericfeedback.consent.titlefeedback.consent.bodyfeedback.consent.acceptTravail à faire
Client (ce ticket —
simpl-resultat)https://feedback.lacompagniemaximus.comau CSPconnect-srcdesrc-tauri/tauri.conf.json(pour futur fetch direct si jamais on abandonne le proxy Rust)reqwestsi pas déjà présente danssrc-tauri/Cargo.tomlsend_feedback(app_id, content, user_id?, context?)danssrc-tauri/src/commands/feedback_commands.rs— POST versfeedback-api, retourneResult<FeedbackResult, String>src-tauri/src/lib.rssrc/services/feedbackService.ts— wrapperinvoke("send_feedback", ...)+ typage TSsrc/hooks/useFeedback.ts— state machine (idle → sending → success → error) viauseReducersrc/components/settings/FeedbackDialog.tsx— Dialog avec textarea, compteur, 3 checkboxes, handling des codessrc/components/settings/FeedbackConsentDialog.tsx— modal one-time consentement privacysrc/components/settings/LogViewerCard.tsx— ajouter bouton "Envoyer un feedback" qui ouvre le dialogsrc/services/logService.ts—getRecentErrorLogs(n)pour extraire les N derniers warn/error formatés en stringuserAgent:"Simpl'Résultat/<version> (<os>)"viatauri::app_handle().package_info()+tauri_plugin_os(si pas déjà en deps, ajouter)feedbackConsentAccepted(localStorage ou config profile)feedback.*danssrc/i18n/locales/fr.json+en.json(table wording ci-dessus)docs.*dans les deux locales — divulguer le canal de feedback externedocs/guide-utilisateur.md— section feedback## [Unreleased]→AddedCross-project
maximus/la-compagnie-maximus: MAJdocs/feedback-hub-ops.mdregistre apps — ajouter lignesimpl-resultat(app_id, placement "Card Settings", CORS = — proxy Rust, date) — issue de tracking créée séparémentmaximus/simpl-feedback-api: aucun changement (proxy Rust, whitelist figée par convention)maximus/simpl-liste#68 : sibling non bloquant, pas de dépendanceFichiers concernés
src-tauri/tauri.conf.jsonconnect-srcfeedback-apisrc-tauri/src/commands/feedback_commands.rssend_feedback(reqwest POST)src-tauri/src/lib.rssrc-tauri/Cargo.tomlreqwest+tauri-plugin-oséventuelsrc/services/feedbackService.tssrc/hooks/useFeedback.tssrc/components/settings/FeedbackDialog.tsxsrc/components/settings/FeedbackConsentDialog.tsxsrc/components/settings/LogViewerCard.tsxsrc/services/logService.tsgetRecentErrorLogs(n)src/i18n/locales/fr.json+en.jsonfeedback.*+ MAJdocs.*docs/guide-utilisateur.mdCHANGELOG.md+CHANGELOG.fr.md[Unreleased] → AddedSurface de test
SettingsPage,LogViewerCard,authService,logServicefeedbackService.test.ts— invoke wrapper, propagation d'erreursuseFeedback.test.ts— state machine (idle → sending → success/error)logService.test.ts—getRecentErrorLogs(n)filtre correctement info/warn/errorSELECT * FROM feedback_hub.feedbacks WHERE app_id='simpl-resultat' ORDER BY created_at DESC LIMIT 1contextCritères d'acceptation
user_idest envoyé uniquement si checkbox cochée ; sinonnullcontent, pas comme clécontextcustomuserAgentcontient"Simpl'Résultat/<version> (<os>)"feedback_hub.feedbacksavecapp_id="simpl-resultat"et les champs de contexte corrects (test manuel)docs/feedback-hub-ops.mddansla-compagnie-maximusmis à jour (issue de suivi séparée)Complexité estimée
Medium — code client structuré (1 commande Rust, 1 service, 1 hook, 2 composants), pas de changement serveur. Les vrais coûts sont : décisions privacy (consent, divulgation docs), wording i18n aligné multi-apps, tests.
Dépendances
la-suite-booking)