La Grosse Caisse · Surface membre · 21 août 2026

Audit UX de l’app côté membre

Passage en revue intégral de la PWA membre par six audits parallèles en lecture de code : auth & onboarding, accueil & navigation, check-in & QR, roue & tombola & lots, rencontre & collection & chansons, agenda & réservations, plus un balayage transversal du catalogue i18n. Aucun fichier modifié, aucun rendu mesuré — les constats sont lus dans la source, cités fichier par fichier.

6tranches auditées
≈ 120constats MAJOR
≈ 100constats MINOR
7motifs transversaux

1Lecture d’ensemble — sept motifs qui traversent toute l’app

Les six audits ont travaillé sans se voir. Quand le même défaut remonte de deux ou trois tranches indépendantes, ce n’est plus un bug local : c’est un motif de fabrication. Sept se dégagent.

1. Le silence après le geste — le motif dominant

Le membre agit, et l’app ne dit rien. C’est le défaut le plus répété, présent dans les six tranches : le renvoi du code de connexion échoue sans un mot (y compris en 429) ; le check-in réussi n’a aucune phrase de confirmation, ni côté membre ni côté staff ; le like de Rencontre n’a aucun accusé de réception ; l’unmatch échoue en silence ; la participation au tirage refusée (409) ne rend rien ; la proposition de chanson ne confirme qu’en région invisible ; la consommation d’un lot se signale par… une carte qui disparaît. Plusieurs boutons sont morts sans explication (soumission login avec e-mail vide, code incomplet, « Installer » sans capture du prompt).

2. Une navigation amputée, et des impasses réelles

La barre d’onglets a été retirée et remplacée par un lien « Check-in » déclaré TEMPORARY — jamais remplacé (layout.tsx:98-104). Conséquences en chaîne : aucun aria-current, aucun <nav>, /app/messages sans retour en PWA installée, dix libellés « Retour aux mini-apps » qui mènent à un écran qui n’existe plus (redirection vers l’accueil). Trois écrans sont carrément inatteignables ou morts : « Mes matchs » (aucun lien depuis l’annuaire alors qu’une pastille le compte), le scanner de lots (rewards/scan, zéro point d’entrée), et la tuile SONG SUGGESTIONS (slug song-suggestions sans route — le shadowing annoncé par songs/page.tsx n’a jamais lieu).

3. Des listes tronquées en silence — la pagination n’est consommée nulle part

Toutes les routes paginent et renvoient hasMore ; aucun écran membre ne le lit : messages (30), agenda (30), matchs (30), fil de conversation (50), collection (60), réservations (30), annuaire (30). grep "hasMore\|page=" sur (member)/app → zéro. Un membre avec 31 matchs en perd un, et la conversation du 31ᵉ devient « introuvable ». Le calendrier de l’agenda, lui, interroge une route non paginée : il affiche des pastilles sur des jours que la liste (page 1 seulement) déclare vides.

4. Des écrans figés au montage — rien ne se rafraîchit jamais

Aucun écran ne réagit à visibilitychange, au retour de focus ni au temps qui passe : le QR membre expire (TTL 5 min) sans signal ni geste de rafraîchissement pendant que expiresAt est reçu et jeté ; l’écran check-in ne voit pas le pointage fait par le staff ; le fil de chat ne reçoit jamais un message entrant (même pas un bouton « Actualiser », que l’annuaire possède) ; la tombola arrête son polling pile avant la validation que le gagnant attend devant le bar ; les réservations restent « En attente » après la décision de l’équipe ; nowIso figé au rendu laisse un lot expiré « À utiliser ».

5. Des erreurs qui mentent ou jargonnent

Trois écrans affichent des secondes brutes (« réessayez dans 3601 secondes », et « 0 secondes » quand l’en-tête Retry-After manque — le bug Number(null)===0 est copié-collé dans trois fichiers). Pire, plusieurs messages affirment le contraire de la vérité : « Code envoyé à… » alors que l’envoi SMTP a échoué (la route avale l’erreur et répond 202) ; « Reconnectez-vous » sur une panne réseau avec session valide ; « La roue n’a pas pu être chargée » pour un échec de tour ; « Votre code n’a pas pu être vérifié » alors que le lot a été attribué ; une panne de lecture de présence rendue comme « vous n’êtes pas présent » ; une recherche de chansons définitivement morte présentée comme indisponible « pour le moment ». Et beaucoup de refus précis (conversation fermée, compte suspendu, quota de 5 propositions) sont repliés sur un générique « Réessayez » — invitation à réessayer un geste garanti d’échouer.

6. Un vocabulaire produit jamais arrêté, une typographie française en friche

Quatre mots pour un des trois bars (adresse / lieu / établissement / endroit — dont deux dans un même bloc de trois lignes) ; « staff » contre « équipe » pour les mêmes personnes ; trois noms pour le geste de présence ; « lot » et « gain » dans la même phrase ; deux marques (« La Grosse App » à l’écran, « La Grosse Caisse » dans l’onglet) ; deux mini-apps quasi homonymes (« ROUE DE LA FORTUNE » ouvre « La roue », à côté de « LA GRANDE ROUE »). Mesuré au catalogue : 0 espace insécable contre 61 espaces ordinaires avant : ; ! ?, 42 apostrophes typographiques contre 381 droites (mélangées dans une même phrase), cinq clés en « (s) » (« 1 lot(s) ») alors que le motif singulier/pluriel existe trois lignes plus loin, et un unique tutoiement — « Un tour t’attend » — posé sur l’accueil, l’écran le plus vu (trouvé indépendamment par trois audits).

7. Les filets transverses n’existent pas

Aucun error.tsx, not-found.tsx ni loading.tsx sous (member)/app (l’admin et l’encodeur ont les leurs) : toute exception ou URL périmée rend l’écran Next par défaut, en anglais, sans retour, dans une PWA installée sans chrome navigateur. Aucun onboarding : les consentements naissent tous à false, donc aucune notification ne partira jamais, et le geste requestPermission n’est armé nulle part — l’interrupteur du profil promet ce qui ne peut pas arriver. Les deep links sont perdus hors de trois préfixes (une notification vers un profil ou l’agenda dépose le membre sur l’accueil), et la reprise du QR staff perd son ?p=. Les navigations n’ont aucun indicateur (prefetch=false + pas de loading.tsx) : sur réseau de bar, un tap semble ne pas avoir marché.

2À corriger en premier

Classement par gravité vécue : ce qui trompe le membre ou casse un parcours passe avant ce qui l’agace.

#DéfautPourquoi c’est prioritaire
1Flux de connexion : « Code envoyé » sur échec SMTP, renvoi silencieux, décompte de renvoi écrasé après 1 s, boutons morts muetsC’est l’unique porte d’entrée du produit, et elle peut affirmer le faux sans issue de secours.
2Fil de chat Rencontre affiché à l’envers (plus récent en haut, message envoyé ajouté en bas), sans horodatage, sans rafraîchissement, plafonné à 50Le chat est inutilisable au sens propre : une conversation ne se lit pas, un message entrant n’arrive jamais.
3Écrans inatteignables : « Mes matchs », scanner de lots, tuile SONG SUGGESTIONS → impasse [slug]Des fonctionnalités livrées et testées que personne ne peut atteindre.
4Navigation membre : stopgap « Check-in » jamais remplacé, « Retour aux mini-apps » ×10 vers un écran disparu, /app/messages sans retourToute la surface en dépend ; en PWA installée il n’y a pas de bouton retour de secours.
5Check-in : aucune confirmation de succès, éjection auto vers la roue avant lecture, re-POST à chaque remontage (quota grillé), QR expirable sans gesteLe rituel central du produit, en conditions réelles (file, bar sombre, réseau faible).
6error.tsx / not-found.tsx / loading.tsx absents côté membreTrois fichiers standards ; sans eux, chaque panne rend un écran Next anglais sans issue.
7Onboarding absent → consentements à false, requestPermission jamais appelé : le push est mort par constructionToute la promesse « notifications » (matchs, réservations, lots) repose dessus.
8Pagination jamais consommée (7 listes tronquées en silence) + calendrier qui contredit la listePerte de données invisible ; casse aussi des parcours (conversation « introuvable »).
9Erreurs 429 en secondes brutes (3601 s / 0 s, trois écrans), refus précis repliés sur « Réessayez »Même bug copié trois fois ; les clés i18n justes existent déjà et ne sont pas branchées.
10Blocage Rencontre irréversible côté app (la route DELETE existe, aucun consommateur), erreurs d’action affichées derrière le scrim du dialogueGeste de sécurité sans porte de sortie ni retour visible.
11Fiche agenda sans date, soirée qui disparaît de la liste à l’heure où elle commence, réservations sans année ni passé/à venirL’axe du temps — la matière première de ces deux mini-apps — est perdu.
12a11y des moments : roue muette 4,6 s, régions aria-live montées avec leur contenu (donc muettes) sur claim/consommation/tombola, « aujourd’hui » invisible au lecteur d’écranLe défaut « live region montée pleine » a déjà été mesuré et corrigé sur la roue ; le correctif n’a pas franchi les frontières d’unité.

3Tranche 1 — Auth, onboarding, installation, offline, légal (18 MAJOR, ≈15 MINOR)

4Tranche 2 — Accueil, layout, navigation, profil, messages (18 MAJOR, ≈15 MINOR)

5Tranche 3 — Check-in, QR membre, tag, vue staff (15 MAJOR, 15 MINOR)

6Tranche 4 — Roue, tombola, lots & QR de réclamation (18 MAJOR, ≈24 MINOR)

7Tranche 5 — Rencontre, collection, chansons (31 MAJOR, ≈15 MINOR)

8Tranche 6 — Agenda, réservations, catalogue i18n (22 MAJOR, ≈15 MINOR)

9Recommandations

A. Trois décisions produit à prendre avant tout mandat

  1. Arrêter le lexique. Un glossaire normatif court (une page) : le mot pour un des trois bars, le mot pour le geste de présence, staff ou équipe, lot (et bannir gain/récompense côté membre), le nom de la marque, et renommer l’une des deux roues. Sans cette décision, chaque vague retranchera localement et différemment — c’est exactement ce que le balayage a mesuré.
  2. Décider la navigation membre. Le stopgap « Check-in » dure depuis sa création ; soit livrer U-B1c (« MA SOIRÉE »), soit rétablir une barre — mais trancher, car dix libellés, l’absence d’aria-current et les impasses de retour en découlent.
  3. Décider l’onboarding. Sans lui : consentements à false, push mort, documents légaux non lus, geste de permission jamais posé. C’est une contrainte produit déjà écrite (iOS ≥ 16.4) restée sans propriétaire.

B. Mandats correctifs groupés (un mandat par chaîne de fichiers disjointe)

  1. Flux d’entréeauth-ui + api/auth : sincérité de l’envoi du code, décompte de renvoi, erreurs du renvoi et du 429 (formatage minutes partagé), boutons morts, retour de session expirée, deep links (paramètre de retour émis côté UI, cookie de reprise avec query).
  2. Coquille membrelayout + racines : error.tsx / not-found.tsx / loading.tsx, conditionnement du raccourci Check-in, retour sur /app/messages, libellés de retour, tuile songs (slug ou route), état nominal du cadre [slug].
  3. Check-in & QR : confirmation explicite (membre + staff), rafraîchissement sur visibilité + échéance + geste manuel du QR, mémorisation du check-in par token (fin du re-POST), distinction des causes de panne de la carte, écran rateLimited avec issue.
  4. Rencontre : sens du fil + horodatages + rafraîchissement manuel + pagination, lien « Mes matchs » persistant, accusé de like, déblocage (brancher la route existante), erreurs d’action dans le dialogue, mapping des i18nKey serveur (l’idiome existe dans songs).
  5. Roue / tombola / lots : lien vers le lot gagné, annonces pendant/après la rotation et la participation, reprise du polling jusqu’à validation, point d’entrée du scanner + rescan possible + arrêt réel, confirmation de consommation + heure côté historique, régions live corrigées (le correctif de la roue, propagé).
  6. Agenda / réservations : date sur la fiche, filtre endsAt, « aujourd’hui » marqué (visuel + a11y), cohérence calendrier/liste, année + partition passé/à venir, confirmation de réservation, lien check-in dans l’erreur.
  7. Pagination transversale : un motif « voir plus » partagé, appliqué aux sept listes — c’est un seul geste de conception répété, pas sept corrections locales.
  8. Lot i18n (spec-writer d’abord, pour le lexique) : insécables, apostrophes, pluriels, capitales, tutoiement, rapatriement des textes en dur (decision-notice.ts, rejection-notice.ts) — puis un gate textuel qui verrouille (espace avant ponctuation double, apostrophe droite, « (s) », tutoiement sous ses deux apostrophes) pour que la dette ne se reforme pas.

C. Outillage — convertir les inconnues que cet audit a payées

  1. Élargir la matrice de viewports aux écrans jamais mesurés : /app/login/code (traversé, jamais mesuré — c’est écrit dans le spec du test), /app/offline, /app/legal, la grille du calendrier, la tombola à 500 participants.
  2. Les E2E doivent passer par les liens, pas par goto() : la tuile songs morte et le scanner inatteignable sont invisibles précisément parce que les tests naviguent à l’URL. Au moins un scénario par mini-app doit partir du hub.
  3. Sonde « région live montée pleine » : le défaut est mesuré, documenté dans wheel-screen.tsx, et réapparu dans trois tranches — il mérite un contrôle rejouable.
  4. Mesurer au banc les SUPPOSÉ avant de les mandater : gel du précache hors-ligne, badge cassable entre chiffres, arc SVG à 1 participant, transitionend manquant, fraîcheur du badge de non-lus au retour navigateur.

10Méthode et limites

Six agents reviewers indépendants (contextes frais, tranches disjointes), lecture seule sur l’arbre main (5754327), chaque constat cité fichier + ligne ou commande + sortie collée. Les agents ont distingué Prouvé (lu dans la source) de Supposé (raisonnement non exécuté) ; plusieurs ont écarté eux-mêmes leurs faux positifs (labelable elements, palier --land-0, ellipses en commentaire). Aucun rendu n’a été observé : ni 320 px, ni lecteur d’écran, ni banc — conformément à la règle du projet, une mise en page non vue à 320 px n’a pas été vue, et ces constats-là sont marqués comme non mesurés, jamais comme verts. Les recouvrements entre tranches (raccourci Check-in, tutoiement unique, secondes brutes, pagination, apostrophes) ont été comptés une fois dans la synthèse : trouvés par deux ou trois audits aveugles l’un à l’autre, ce sont les signaux les plus sûrs du rapport.

Constats positifs, pour l’équilibre : la discipline 320 px est réelle dans le CSS (grilles minmax, overflow-wrap, cibles tactiles), les focus traps des dialogues sont corrects, le vouvoiement est constant à une chaîne près, les gardes serveur (session revalidée, 404-jamais-403, portée) sont solides. Le produit est bien construit dans chaque écran ; il se casse entre les écrans et après les gestes.