Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.snakysec.com/llms.txt

Use this file to discover all available pages before exploring further.

UX Audit — Problèmes détectés

Phase 2 — Inventaire des doublons, orphelins, incohérences et pertes de contexte Méthodologie : analyse statique du code (platform/src/app/** et platform/src/components/**). Chaque problème est sourcé par un chemin de fichier ; les cas marqués (à confirmer) méritent vérification produit. Tri : par impact décroissant dans chaque catégorie (fort > moyen > faible).

DOUBLONS

PROB-DUP-01 — Lancement d’un audit accessible via 2 surfaces différentes (impact moyen)

  • Pages : /dashboard/clients/[id] (header bouton <TriggerAuditButton>) et /dashboard/clients/[id]/documents (lien texte “Lancer un audit” dans empty state)
  • Description : Le bouton primaire <TriggerAuditButton> ouvre une modal complète (framework + product areas), tandis que le lien dans le hub documents redirige simplement vers la page client (pas vers une modal). 2 chemins, expérience non équivalente.
  • Code : platform/src/app/dashboard/clients/[id]/trigger-audit-button.tsx vs platform/src/app/dashboard/clients/[id]/documents/page.tsx:357-360

PROB-DUP-02<GuideFilterDialog> exposé en parallèle dashboard et portal avec 2 variants (impact moyen)

  • Pages : /dashboard/clients/[id] (header) et /portal/remediation (header)
  • Description : Même composant avec prop variant: "dashboard" | "portal" qui change uniquement le label du bouton et le styling. Côté MSSP, c’est mêlé à 7 autres boutons dans le header client (cf. PROB-CTX-01) ; côté portal il est aux côtés de 2 autres boutons download.
  • Code : platform/src/components/remediation/guide-filter-dialog.tsx (Props.variant)

PROB-DUP-03 — 3 endpoints de téléchargement de plan de remédiation (impact moyen)

  • Pages : /dashboard/clients/[id]/remediation-plan (1 bouton “Download PDF”) + /portal/remediation (2 boutons “Download milestones PDF” + “Download PDF”) + <GrcDocumentCards> (carte “Plan Remédiation”)
  • Description : 3 surfaces qui téléchargent plus ou moins le même artefact PDF (/api/v1/clients/[id]/documents/remediation-plan et /api/v1/clients/[id]/documents/milestones-plan). L’utilisateur a du mal à comprendre la différence.
  • Code :
    • platform/src/app/dashboard/clients/[id]/remediation-plan/page.tsx:73-77
    • platform/src/app/portal/remediation/page.tsx:54-65
    • platform/src/components/grc-document-cards.tsx (type remediation-plan)

PROB-DUP-04 — Téléchargement audit report dupliqué entre <AuditActions> et <DownloadReportButton> (impact faible)

  • Pages : /dashboard/audits/[id] (utilise <AuditActions variant="buttons"> avec PDF/Excel/HTML) et /portal/audits/[id] (utilise <DownloadReportButton>)
  • Description : 2 implémentations distinctes pour télécharger des rapports d’audit. Toujours possible que les comportements divergent (formats supportés, gestion erreurs, naming).
  • Code : platform/src/components/audit-actions.tsx:53-75 vs platform/src/components/download-report-button.tsx

PROB-DUP-05 — Logique de calcul documentContexts dupliquée entre dashboard et portal (impact faible — dette technique)

  • Pages : /dashboard/clients/[id]/documents/page.tsx:135-280 et /portal/documents/page.tsx:135-216
  • Description : Les deux pages reconstruisent indépendamment les classifications domain (isMfa, isCA, isPriv, etc.) et la map documentContexts. Risque de divergence si les regex évoluent d’un côté.
  • Code : 2 copies presque identiques, ~80 lignes chacune.

PROB-DUP-06signOut() callé depuis 3 endroits (impact faible)

  • Pages : Sidebar dashboard footer, PortalSidebar footer, Header dropdown user
  • Description : 3 surfaces “Sign Out / Logout” dans le même flow utilisateur (sidebar bottom + header dropdown). Acceptable UX mais incohérent en labels (cf. PROB-INC-04).
  • Code : sidebar.tsx:229, portal-sidebar.tsx:87, header.tsx:98

PROB-DUP-07<ImpersonateClientButton> et <PortalClientPicker> font la même chose (impact faible)

  • Pages : /dashboard/clients (button par client card) et /portal mode admin_no_selection (cards picker)
  • Description : Les deux postent à POST /api/portal/impersonate avec un clientId. La carte sur /dashboard/clients impose à l’admin d’aller chercher le bouton ; le picker sur /portal est plus visible. Comportement et endpoint identiques.
  • Code : platform/src/components/impersonate-client-button.tsx vs platform/src/components/portal-client-picker.tsx

ORPHELINS

PROB-ORPH-01/dashboard/clients/[id]/documents n’a aucun lien direct dans la nav (impact fort)

  • Page concernée : /dashboard/clients/[id]/documents
  • Description : Cette page (hub conformité client GRC, 4 documents PDF générables) n’est référencée par AUCUN lien depuis le client overview header (qui pourtant expose 8 boutons : Edit, Credentials, Findings, Remediation, Guide PDF, Trajectory, CISO, Trigger Audit). Pour y accéder il faut connaître l’URL ou passer via un breadcrumb manuel, ou via des entrées comme “Couverture 220 contrôles” dans /dashboard/documents/technical (qui pointent vers /dashboard/clients/[id], pas /documents).
  • Impact : Une fonctionnalité majeure (génération de 4 documents GRC clients) est cachée.
  • Code : platform/src/app/dashboard/clients/[id]/documents/page.tsx

PROB-ORPH-02/dashboard/clients/[id]/remediation-plan accessible uniquement depuis le hub orphelin documents (impact fort)

  • Page concernée : /dashboard/clients/[id]/remediation-plan
  • Description : La page du plan exécutif read-only n’a pas de bouton dans le header client. Le bouton header s’appelle “Remediation” et pointe vers /remediation (le workspace DnD), pas vers /remediation-plan (la vue exécutive). Le seul lien est “Voir tout (X findings)” sur /dashboard/clients/[id]/documents lui-même orphelin (cf. PROB-ORPH-01).
  • Impact : Vue exécutive du plan inaccessible aux MSSP_ADMIN sauf URL directe.
  • Code : platform/src/app/dashboard/clients/[id]/remediation-plan/page.tsx ; lien depuis docs hub : documents/page.tsx:461-465

PROB-ORPH-03/dashboard/clients/[id]/controls/[controlId] accessible uniquement par cellule de table (impact moyen)

  • Page concernée : /dashboard/clients/[id]/controls/[controlId]
  • Description : La page détail d’un contrôle est une page riche (description, mappings réglementaires CIS/ISO/NIS2/DORA/eIDAS/RGPD, DICT, history). Elle est uniquement atteignable en cliquant sur la cellule controlId d’une <ControlResultsTable> (audit detail dashboard ou portal). Pas dans la sidebar, pas dans une liste de contrôles globale.
  • Impact : Difficile à découvrir, et impossible de naviguer entre 2 contrôles consécutifs sans repasser par l’audit.
  • Code : platform/src/app/dashboard/clients/[id]/controls/[controlId]/page.tsx, lien implicite via <ControlResultsTable>

PROB-ORPH-04/dashboard/audits/[id]/diff exclusivement déclenchée par le <CompareSelector> (impact moyen)

  • Page concernée : /dashboard/audits/[id]/diff?vs=<id>
  • Description : Aucun lien direct dans /dashboard/audits (table) ou /dashboard/clients/[id] (history tab). Le <CompareSelector> est imbriqué dans le header de la page detail audit. Le diff N vs N-1 est inaccessible directement, ce qui contre-intuitif puisque cette feature est explicitement indexée dans les libellés “Diff Audit N vs N-1”.
  • Code : platform/src/app/dashboard/audits/[id]/diff/page.tsx ; trigger : audit-diff via <CompareSelector> dans /audits/[id]/page.tsx:279

PROB-ORPH-05/dashboard/clients/[id]/onboarding (sans step) est une route serveur invisible (impact faible — comportement attendu)

  • Page concernée : /dashboard/clients/[id]/onboarding
  • Description : Pas d’UI ; redirige côté serveur vers /onboarding/[step]. Comportement intentionnel (resume) mais le bouton “Resume” du banner client overview pointe vers cette URL même.
  • Code : platform/src/app/dashboard/clients/[id]/onboarding/page.tsx

PROB-ORPH-06/dashboard/settings/notifications n’apparait pas dans la liste i18n des liens settings (impact faible)

  • Page concernée : /dashboard/settings/notifications
  • Description : Le hub settings (/dashboard/settings/page.tsx) construit ses cards depuis settingsLinks (5 entries i18n) puis ajoute manuellement la card Notifications hors loop avec un titre français hardcoded “Notifications email”. Si les autres pages settings sont traduites EN/FR, celle-là est figée FR. Idem pour DR Runbook.
  • Code : platform/src/app/dashboard/settings/page.tsx:45-57 (hardcoded), :8-14 (i18n loop)

PROB-ORPH-07 — Sous-pages settings sans entrée sidebar (impact faible)

  • Pages concernées : /dashboard/settings/users, /audit-log, /api-keys, /access-review, /roles, /notifications
  • Description : Aucune ne figure dans la sidebar — elles sont accessibles uniquement par le hub /dashboard/settings. La sidebar n’a pas non plus de mode “collapsible” pour Settings comme elle l’a pour Documents. L’utilisateur sait qu’il est dans Settings (item actif sidebar) mais doit revenir au hub à chaque fois.
  • Code : sidebar.tsx:198-218 (entrée Settings unique, non collapsible)

PROB-ORPH-08 — Page d’erreur “Forbidden” inexistante en UI (impact faible — à confirmer)

  • Page concernée : redirect /dashboard?error=forbidden (cf. controls/[controlId]/page.tsx:101, help/dr/layout.tsx:21)
  • Description : Plusieurs gardes redirigent vers /dashboard?error=forbidden mais la page /dashboard ne traite pas le query param error. L’utilisateur arrive silencieusement sur le dashboard sans toast ni indication.
  • Code : platform/src/app/dashboard/page.tsx (pas de read sur searchParams.error)

INCOHÉRENCES

PROB-INC-01 — Mix EN/FR généralisé dans les labels UI (impact fort)

  • Pages concernées : multiples
  • Description :
    • <PortalSidebar> : labels EN hardcoded (“Overview”, “Audits”, “Findings”, “Remediation”, “Documents”, “Logout”) alors que toute la plateforme côté MSSP est traduite via next-intl
    • <DashboardFilters> : “All clients”, “7 days”, “30 days”, “90 days” hardcoded EN
    • <AuditFilters> : “All statuses”, “Pending”, “Running”, “Completed”, “Partial”, “Failed”, “Cancelled” hardcoded EN
    • /dashboard/settings/users/page.tsx : labels FR hardcoded (“Utilisateurs”, “Rôle”, “Accès clients”, “Dernière connexion”) sans i18n
    • /dashboard/settings/audit-log/audit-log-content.tsx : ~30 strings FR hardcoded (“Audit log”, “Traçabilité plateforme”, “Filtres”, “Acteur”, “Ressource”, “Toutes”, “Réinitialiser”, “Charger plus”, etc.)
    • /portal/audits/[id]/page.tsx : “Passed”, “Failed”, “Manual Review”, “Compliance” en EN
    • /portal/documents/page.tsx : titre + description FR hardcoded
    • <EditClientPage> : labels formulaire EN (“Organization Name”, “Slug (identifier)”, “M365 Tenant ID”) + descriptions FR (“Active la planification…”, “Les audits plus anciens…”). Bouton “Save Changes” / “Cancel” EN.
  • Impact : Casse le <LanguageSwitcher> — toggle FR ne traduit qu’une partie de la plateforme.
  • Code : portal-sidebar.tsx:24-30, dashboard-filters.tsx:20-24, audits/audit-filters.tsx:19-27, settings/users/page.tsx:78-99, settings/audit-log/audit-log-content.tsx, portal/audits/[id]/page.tsx:51-61, portal/documents/page.tsx:67, clients/[id]/edit/page.tsx:225-457

PROB-INC-02 — Labels “Lancer un audit” vs “Trigger” / “Launch” (impact moyen)

  • Pages concernées : <TriggerAuditButton>, /dashboard/clients/[id]/documents
  • Description :
    • <TriggerAuditButton> utilise t("launch") → “Lancer un audit” en FR
    • /dashboard/clients/[id]/documents:357 lien hardcoded “Lancer un audit”
    • L’API et les commits parlent de “trigger audit”
    • /portal parle de “Recent audits” mais pas de relancer
    • <AuditActions> parle de “retry” et “sync”
  • Code : trigger-audit-button.tsx, clients/[id]/documents/page.tsx:357-360

PROB-INC-03 — Boutons “Voir” avec comportements différents (impact moyen)

  • Pages concernées :
    • /portal/audits table cell “Voir” → /portal/audits/[id] (link)
    • <ImpersonateClientButton> “Voir comme ce client” → POST + redirect /portal
    • <PortalClientPicker> “Voir comme ce client” → POST + redirect /portal
    • /dashboard/clients/[id]/documents:464 “Voir tout (X findings)” → /dashboard/clients/[id]/remediation-plan
  • Description : 4 actions différentes labellisées “Voir…”. L’utilisateur ne peut pas anticiper si c’est une nav simple ou une action serveur (impersonate write-side-effect).
  • Code : portal/audits/page.tsx:94, impersonate-client-button.tsx:60-62, portal-client-picker.tsx:99-103, clients/[id]/documents/page.tsx:464

PROB-INC-04 — “Sign Out” vs “Logout” vs “Quitter” (impact moyen)

  • Pages concernées : sidebar dashboard, portal-sidebar, header dropdown, portal-impersonation-banner
  • Description :
    • Sidebar dashboard : tCommon("signOut") → “Se déconnecter” (FR)
    • PortalSidebar : “Logout” hardcoded EN
    • Header dropdown : tCommon("signOut") → “Se déconnecter” (FR)
    • PortalImpersonationBanner : “Quitter” hardcoded FR (action différente : DELETE /api/portal/impersonate)
  • Code : sidebar.tsx:232, portal-sidebar.tsx:90, header.tsx:100, portal-impersonation-banner.tsx:45

PROB-INC-05 — Hiérarchie de breadcrumb incohérente entre routes client (impact moyen)

  • Pages concernées : sous-routes /dashboard/clients/[id]/*
  • Description :
    • Pages avec <Breadcrumb> shadcn complet (4 niveaux Tableau de bord > Clients > nom > sous-page) : /edit, /secrets, /findings, /remediation, /remediation-plan, /trajectory, /documents, /controls/[controlId]
    • Pages SANS breadcrumb mais avec back arrow seul : /dashboard/clients/new, /dashboard/settings/users, /dashboard/settings/api-keys, /dashboard/settings/audit-log, /dashboard/settings/notifications
    • Pages SANS aucun retour visible : /dashboard/clients/[id]/onboarding/[step] (utilise stepper sidebar à la place)
    • /portal/audits/[id], /portal/findings, /portal/remediation, /portal/documents : aucun breadcrumb ni back arrow (cf. PROB-CTX-02)
  • Code : pattern <Breadcrumb> cohérent côté clients/[id]/* mais cassé côté settings/* et portal/*

PROB-INC-06 — Header client : 8 boutons inline + 1 dropdown vs <AuditActions variant="buttons"> 7 boutons inline (impact moyen)

  • Pages concernées : /dashboard/clients/[id] header et /dashboard/audits/[id] header
  • Description : Convention de header “stack horizontal de boutons” surchargée. Sur mobile et petits écrans, ça wrap mal. Aucun primary/secondary visuel — tous variant outline sauf le primary (TriggerAuditButton). Pas de groupement (Identity vs Operations vs Reports).
  • Code : clients/[id]/page.tsx:146-188, audits/[id]/page.tsx:264-281, audit-actions.tsx:131-245

PROB-INC-07 — Filtres dashboard vs filtres audits : design pattern divergent (impact moyen)

  • Pages concernées : /dashboard (DashboardFilters) et /dashboard/audits (AuditFilters)
  • Description :
    • DashboardFilters : Select client + groupe de 3 boutons toggle pour periode (7d/30d/90d) avec UI custom
    • AuditFilters : 2 Select (status + client)
    • Pourtant les 2 sont des filtres URL-synced à la même fonction updateParam. Convention divergente.
  • Code : dashboard-filters.tsx:46-82, audits/audit-filters.tsx:51-86

PROB-INC-08 — Sidebar 2 styles différents pour entrées actives (impact faible)

  • Pages concernées : sidebar.tsx (top items, documents sub-items, settings)
  • Description : 3 patterns de styling actif :
    • Top nav : bg-primary/10 text-primary font-semibold + variant secondary
    • Documents header (button) : bg-primary/10 text-primary font-semibold mais c’est un <button> plain (pas un <Button> shadcn)
    • Documents sub-items : bg-primary/10 text-primary font-semibold sur un <Button size="sm" variant="ghost">
    • Settings : recopie le pattern top mais sans ChevronDown
  • Code : sidebar.tsx:101-128, 132-150, 156-167, 199-218
  • Pages concernées : /dashboard/clients, /dashboard/settings, /dashboard/documents, /dashboard/help/dr
  • Description : Sur /dashboard/clients, la Card est wrapped dans un <Link> mais le footer <ImpersonateClientButton> ne l’est pas. Sur /dashboard/settings, la Card entière est dans un <Link>. Sur /dashboard/documents, idem. Sur /dashboard/help/dr, idem. Convention “card-as-link” inconsistante.
  • Code : clients/page.tsx:96-160, settings/page.tsx:30-43, documents/page.tsx:239-292, help/dr/page.tsx:90-103

PROB-INC-10 — Boutons CSV / “CSV + before/after” sans label différencié visuellement (impact faible)

  • Pages concernées : /dashboard/settings/audit-log
  • Description : 2 boutons côte à côte (“CSV” et “CSV + before/after”). Le 2e a variant="ghost" au lieu de variant="outline" ; à part ça, même icône, même tooltip-only différenciation. Risque de download accidentel d’un CSV très lourd.
  • Code : audit-log-content.tsx:300-317

PROB-INC-11 — Termes mixés “Findings” vs “Écarts” vs “Open gaps” (impact faible)

  • Pages concernées : multiples
  • Description :
    • DB schema : GapFinding
    • Code utilise gapFindings, openGaps
    • UI : “Findings” côté audit detail summary (i18n EN), “écart” dans <ControlExpandedRow> (FR), “non-conformes” sur /portal/documents
    • /dashboard/clients/[id]/documents parle de “Findings ouverts” et “Findings critiques”
    • <TopCriticalFindings> parle de “Top Critical Findings”
  • Code : référence taxonomique non figée. Cf. clients/[id]/documents/page.tsx:399, 415, portal/documents/page.tsx, audit/control-expanded-row.tsx:39-48

PERTE DE CONTEXTE

PROB-CTX-01 — Pas d’indication d’onglet/de tabs actif sur /dashboard/clients/[id] après reload (impact moyen)

  • Page concernée : /dashboard/clients/[id]
  • Description : <Tabs defaultValue="overview"> n’est pas synchronisé avec un query param. Au reload, on retombe toujours sur “Overview” même si l’utilisateur était sur “History” ou “Findings”. Pas de breadcrumb 4e niveau pour indiquer l’onglet actif.
  • Code : clients/[id]/page.tsx:246

PROB-CTX-02 — Pages portal sans breadcrumb ni back arrow (impact moyen)

  • Pages concernées : /portal/audits/[id], /portal/findings, /portal/remediation, /portal/documents
  • Description : Côté portal client, aucune des sous-pages n’a de breadcrumb ni de bouton de retour. L’utilisateur ne peut revenir qu’en cliquant sur la sidebar. Pour /portal/audits/[id] (qui peut avoir été ouverte depuis /portal/audits ou depuis un email), pas de retour vers la liste. Idem pour le mode impersonate où le banner offre uniquement “Quitter” (qui retourne au dashboard MSSP, pas au portal/audits).
  • Code : portal/audits/[id]/page.tsx:64, portal/findings/page.tsx:46, portal/remediation/page.tsx:43, portal/documents/page.tsx:218

PROB-CTX-03 — Le wizard onboarding ne montre pas la position dans le flow global (impact moyen)

  • Page concernée : /dashboard/clients/[id]/onboarding/[step]
  • Description : <OnboardingShell> affiche un stepper sidebar 1-7 (mais la step 8 = Done est définie dans STEP_LABELS et accessible). Pas de breadcrumb (Tableau de bord > Clients > nom > Onboarding step X). Si l’utilisateur arrive sur cette URL via lien externe, il ne sait pas dans quel client il est ni comment sortir (le banner banner client overview n’existe pas ici).
  • Code : onboarding/wizard-stepper.tsx:36-93, pas d’utilisation de <Breadcrumb>

PROB-CTX-04 — Active audit banner sur /dashboard/clients/[id] n’utilise pas le live monitor (impact moyen)

  • Page concernée : /dashboard/clients/[id]
  • Description : Quand un audit est en cours, un banner “Audit en cours” cliquable apparait. Mais c’est juste un lien — pas de progress bar, pas de stage indicator. Le <AuditLiveMonitor> (SSE complet avec stages) n’est rendu que dans /dashboard/audits/[id].
  • Code : clients/[id]/page.tsx:191-208, audits/[id]/page.tsx:284-294

PROB-CTX-05 — Modales/Dialogs sans titre clair ou contexte (impact moyen)

  • Pages concernées : multiples
  • Description :
    • <AuditActions> confirm t("confirmDelete") (toString JS confirm natif) — pas de modale shadcn, pas de doc sur ce qui sera supprimé
    • clients/[id]/secrets : confirm(t("confirmDelete", {key})) natif aussi
    • <TriggerAuditButton> Dialog : titre t("dialogTitle", { slug }) mais le slug est techy et l’utilisateur perd le contexte du nom client
    • <GuideFilterDialog> : titre opaque, pas d’aperçu de ce que le PDF contient
  • Code : audit-actions.tsx:78, secrets/page.tsx:97, trigger-audit-button.tsx:151

PROB-CTX-06 — Empty states dans /dashboard/clients/[id]/findings peu informatifs (impact moyen)

  • Page concernée : /dashboard/clients/[id]/findings
  • Description : Si filter ne matche rien : <p>{t("emptyFilter")}</p> — pas d’icône, pas de bouton “reset filter”. Pas de breadcrumb 4e niveau ni d’indicateur visuel du filtre actif.
  • Code : clients/[id]/findings/page.tsx:170-172

PROB-CTX-07/dashboard/help/dr/[...slug] enfoui sans hiérarchie de section (impact moyen)

  • Page concernée : /dashboard/help/dr/[...slug]
  • Description : Le viewer markdown affiche le slug brut “docs/dr/runbooks/01-restore-postgres-pitr.md” en footer mais pas de breadcrumb (DR > Runbooks > Restore Postgres). Le sidebar DR (<DrDocsSidebar>) montre la structure, mais quand on partage l’URL ou retourne dessus on ne sait pas quelle “section” on consulte sans inspecter le slug.
  • Code : help/dr/[...slug]/page.tsx:71-80 (pas de breadcrumb)

PROB-CTX-08 — Header DR + sidebar DR + sidebar dashboard = 3 niveaux empilés (impact moyen)

  • Pages concernées : /dashboard/help/dr et sub-routes
  • Description : Le layout DR ajoute un sub-sidebar <DrDocsSidebar> à l’intérieur de <main>. Donc l’écran montre :
    • Sidebar gauche dashboard (64 col)
    • Header dashboard top (16 row)
    • Banner Tampering (conditional)
    • Sidebar gauche <DrDocsSidebar> interne
    • Contenu doc
  • Impact : sur écrans <1280px, il reste très peu de place pour le contenu doc. La hiérarchie de nav crée beaucoup de chrome.
  • Code : dashboard/layout.tsx + help/dr/layout.tsx:37-43

PROB-CTX-09 — Page /dashboard/clients/[id]/edit utilise router.back() pour Cancel (impact faible)

  • Page concernée : /dashboard/clients/[id]/edit
  • Description : <Button onClick={() => router.back()}>Cancel</Button> — comportement imprévisible si l’utilisateur arrive depuis un lien externe (pas d’historique). Le breadcrumb pointe vers /clients/[id] mais le bouton Cancel ne le fait pas.
  • Code : clients/[id]/edit/page.tsx:457-459

PROB-CTX-10 — Mode prévisualisation (impersonate) sort vers /dashboard au lieu de /dashboard/clients (impact faible)

  • Page concernée : <PortalImpersonationBanner> “Quitter”
  • Description : Action DELETE /api/portal/impersonate puis router.push("/dashboard"). Pourtant l’admin venait de /dashboard/clients via <ImpersonateClientButton>. Casse le flow naturel “je teste un client puis je reviens à la liste”.
  • Code : portal-impersonation-banner.tsx:17

PROB-CTX-11EditClientPage n’a pas d’erreur form globale visible (impact faible)

  • Page concernée : /dashboard/clients/[id]/edit
  • Description : En cas d’erreur PUT, c’est uniquement un toast destructif. Si le form a 30 champs et que la validation serveur échoue sur l’un d’eux, le toast donne un message court et l’utilisateur doit chercher le champ. Pas de scroll-to-error.
  • Code : clients/[id]/edit/page.tsx:160-167

PROB-CTX-12 — Multi-sélection product areas dans <TriggerAuditButton> peu lisible (à confirmer)

  • Page concernée : <TriggerAuditButton> modal
  • Description : Popover combobox avec checkboxes ; le label affiché (“3 sélectionnés”, “tout sélectionné”, “Entra, Exchange, Teams”) change selon le nombre. Le bouton Launch n’aperçoit pas la sélection à côté. L’utilisateur peut s’embrouiller entre “tous” et “0 sélectionnés”.
  • Code : trigger-audit-button.tsx:81-87, 175-227

Bugs techniques détectés (hors scope UX strict)

BUG-01STEP_ORDER dans <OnboardingShell> exclut step 8 mais le wizard a bien 8 étapes

  • Fichier : platform/src/components/onboarding/wizard-stepper.tsx:15
  • Description : const STEP_ORDER: StepIndex[] = [1, 2, 3, 4, 5, 6, 7]; mais VALID_STEPS côté [step]/page.tsx inclut [1,2,3,4,5,6,7,8]. Step 8 (Done) est rendu mais ne sera jamais affiché dans la stepper sidebar.

BUG-02 — Document categories: lien “Couverture 220 contrôles” pointe vers /dashboard/clients/[id] (page client) au lieu de la page de couverture

  • Fichier : platform/src/app/dashboard/documents/technical/page.tsx:28
  • Description : viewPath: "/dashboard/clients/{clientId}" pour l’item control-coverage. Ne mène pas vers une page dédiée de couverture des 220 contrôles, mais redirige sur l’overview client. Entrée non-fonctionnelle pour son but déclaré.

BUG-03<DashboardFilters> redirige toujours vers /dashboard même si on est ailleurs

  • Fichier : platform/src/components/dashboard-filters.tsx:42
  • Description : router.push(\/dashboard?$`)` hardcodé. Si jamais ce composant est réutilisé sur une autre page, casse la nav.
  • Fichier : platform/src/app/dashboard/settings/page.tsx:50-51
  • Description : <CardTitle>Notifications email</CardTitle> + <p>Préférences de réception...</p> directement en FR alors que le reste utilise t(\links.$.title`)`.

BUG-05<DownloadReportButton> portal vs <AuditActions> MSSP : 2 implémentations divergentes

  • Fichiers : platform/src/components/download-report-button.tsx, platform/src/components/audit-actions.tsx
  • Description : <DownloadReportButton> côté portal n’expose probablement que PDF (à vérifier sur le code) tandis que <AuditActions> expose PDF/Excel/HTML. Si le client portal veut un Excel, il ne peut pas l’avoir.

BUG-06/dashboard?error=forbidden non géré

  • Fichier : platform/src/app/dashboard/page.tsx
  • Description : Plusieurs gardes redirigent vers cette URL avec ?error=forbidden mais la page ne lit pas ce param et ne montre aucun toast (cf. PROB-ORPH-08).

Synthèse priorités

CatégorieTotalImpact fortImpact moyenImpact faible
DOUBLONS7034
ORPHELINS8224
INCOHÉRENCES11164
PERTE DE CONTEXTE12084
TOTAL UX3831916
Bugs techniques6
Top 5 risques utilisateur :
  1. PROB-ORPH-01 — Hub documents client orphelin (fonctionnalité majeure invisible)
  2. PROB-ORPH-02 — Plan exécutif remediation orphelin (vue exec inaccessible)
  3. PROB-INC-01 — Mix EN/FR généralisé casse le LanguageSwitcher
  4. PROB-CTX-02 — Portal client sans aucun retour ni breadcrumb
  5. PROB-INC-06 — Surcharge des headers (8 boutons inline) crée du chaos visuel sur petits écrans