[Majeur] Présence : IsOnline booléen, un onglet fermé ou une déconnexion brutale fausse le statut et coupe le temps réel #99

Closed
opened 2026-10-28 10:31:58 +00:00 by asventi · 0 comments
Owner

Gravité : Majeur
Rapports QA d'origine : FRIENDS-14, PROFILE-15, FRIENDS-15, PROFILE-16

KeepGroupedHub (lignes 19 et 51) stocke un booléen : fermer un onglet passe l'user Offline pour tous et coupe le temps réel de ses autres onglets ; après un crash, aucun Offline n'est diffusé.

Détails des rapports

[FRIENDS-14] Multi-onglets : fermer un onglet passe l'utilisateur "Offline" pour tous et coupe le temps réel des autres onglets — Gravité : Majeur
  • Où : hub SignalR (KeepGroupedHub.OnDisconnectedAsync) + routes/dashboard.tsx (beforeunload) ; CreateMessageCommand (user.IsOnline)
  • Étapes : 1. B ouvre 2 onglets (même session) : onglet 1 sur le DM A<->B, onglet 2 sur /messages. A est sur /messages/all (B apparaît "Online"). 2. B ferme l'onglet 2. 3. A envoie un message dans le DM (API, 201).
  • Attendu : B reste "Online" (un onglet ouvert) et reçoit le message en direct dans l'onglet 1.
  • Obtenu : (a) chez A, B passe "Offline" (friends_25_presence_after_close_tab2.png) alors qu'un onglet est toujours ouvert ; (b) l'onglet 1 de B ne reçoit PAS le message en direct (friends_26_B_tab1_no_realtime.png) : il n'apparaît qu'après rechargement. Tous les événements temps réel NewMessage/UpdateMessage/RemoveMessage ne sont envoyés qu'aux users dont IsOnline est vrai en base, or OnDisconnectedAsync met IsOnline=false à la fermeture de n'importe quelle connexion.
  • Preuve : sortie de scripts/friends/ui8.py ("A view after B closes tab2: ... Offline", "B tab1 got message live: False").
  • Cause probable : backend/API/KeepGroupedHub.cs:19 et :51 (booléen unique au lieu d'un compteur de connexions) ; Channels/Messages/Create/CreateMessageCommand.cs:49 (filtre IsOnline inutile : Clients.User(...) suffit). Côté client, frontend/src/routes/dashboard.tsx:38-41 (handleUnload envoie Offline sans tenir compte des autres onglets).
[PROFILE-15] Présence : fermer UN onglet d'un user connecté dans plusieurs onglets le fait passer "Offline" pour tous les autres — Gravité : Mineur
  • Où : Accueil > panneau Members (autre session), temps réel SignalR
  • Étapes : 1. User A connecté dans l'onglet 1 (visible) ; user B voit A dans "ONLINE". 2. A ouvre un 2e onglet (B voit toujours A "ONLINE"), puis le ferme.
  • Attendu : A reste "Online" (l'onglet 1 est toujours ouvert et visible).
  • Obtenu : B voit A passer dans "OFFLINE" (3 s après) et il y reste, même après un bring_to_front de l'onglet 1 ; seul un changement de visibilité ou un reload de A le corrigera.
  • Preuve : sortie de script (B sees A: OFFLINE — 64 après fermeture du 2e onglet).
  • Cause probable : frontend/src/routes/dashboard.tsx:38-44 (handleUnload envoie setSelfActivity(Offline) à chaque onglet) ; l'état de présence est purement client (activity.hook.ts), aucun comptage de connexions par user côté hub (backend/API/KeepGroupedHub.cs).
[FRIENDS-15] Présence figée après une déconnexion abrupte (le serveur ne diffuse pas "Offline") — Gravité : Mineur
  • Où : ActivityLabel / onglet "Online" / ProfilePic status ; hub OnDisconnectedAsync
  • Étapes : 1. A sur /messages/online, B (ami) en ligne. 2. B ferme brutalement sa page (page.close() sans beforeunload, équivalent crash / coupure réseau / mobile). 3. Attendre 12 s.
  • Attendu : B disparaît de "Online" chez A.
  • Obtenu : B reste dans "ONLINE — 1" avec le statut "Away" (dernier visibilitychange) indéfiniment ; il faut recharger la page de A pour qu'il disparaisse. La présence ne repose que sur des événements envoyés par le client (routes/dashboard.tsx beforeunload) ; KeepGroupedHub.OnDisconnectedAsync ne notifie personne.
  • Preuve : sortie de scripts/friends/ui9.py ("A online tab after B abrupt close (4s): ... Away", idem à +12 s, vide après reload).
  • Cause probable : backend/API/KeepGroupedHub.cs:44-54 (pas de Clients.Others.SendAsync("OtherActivityUpdated", userId, Offline)).
[PROFILE-16] Présence : après une déconnexion brutale (crash navigateur/onglet tué/réseau coupé) le user reste affiché "Away/Online" indéfiniment pour les autres — Gravité : Mineur
  • Où : Accueil > Members, compteur "x/y Online"
  • Étapes : 1. A et B connectés. 2. Fermer le contexte de A sans beforeunload (kill du navigateur). 3. Observer B pendant 15 s, puis recharger B.
  • Attendu : A passe "Offline" pour B quand la connexion SignalR de A tombe.
  • Obtenu : B voit A "AWAY — 3" (dernier état connu) au-delà de 15 s ; après un reload de B, A apparaît "OFFLINE". OnDisconnectedAsync met IsOnline=false en base mais ne diffuse rien aux autres clients ; IsOnline n'est lu nulle part.
  • Cause probable : backend/API/KeepGroupedHub.cs:41-54 (pas de Clients.Others.SendAsync("OtherActivityUpdated", userId, Offline) dans OnDisconnectedAsync).
  • Note : fermeture normale d'un onglet unique, bascule onglet masqué -> "Away" (immédiate), retour -> "Online", late-joiner (AskOthersActivity) fonctionnent correctement.

Trouvé par une campagne de tests QA automatisés (agents Claude, Playwright) sur l'environnement de dev. Les captures citées sont locales et non jointes.

**Gravité :** Majeur **Rapports QA d'origine :** FRIENDS-14, PROFILE-15, FRIENDS-15, PROFILE-16 `KeepGroupedHub` (lignes 19 et 51) stocke un booléen : fermer un onglet passe l'user Offline pour tous et coupe le temps réel de ses autres onglets ; après un crash, aucun Offline n'est diffusé. ## Détails des rapports <details><summary>[FRIENDS-14] Multi-onglets : fermer un onglet passe l'utilisateur "Offline" pour tous et coupe le temps réel des autres onglets — Gravité : Majeur</summary> - Où : hub SignalR (`KeepGroupedHub.OnDisconnectedAsync`) + `routes/dashboard.tsx` (`beforeunload`) ; `CreateMessageCommand` (`user.IsOnline`) - Étapes : 1. B ouvre 2 onglets (même session) : onglet 1 sur le DM A<->B, onglet 2 sur /messages. A est sur `/messages/all` (B apparaît "Online"). 2. B ferme l'onglet 2. 3. A envoie un message dans le DM (API, 201). - Attendu : B reste "Online" (un onglet ouvert) et reçoit le message en direct dans l'onglet 1. - Obtenu : (a) chez A, B passe "Offline" (`friends_25_presence_after_close_tab2.png`) alors qu'un onglet est toujours ouvert ; (b) l'onglet 1 de B ne reçoit PAS le message en direct (`friends_26_B_tab1_no_realtime.png`) : il n'apparaît qu'après rechargement. Tous les événements temps réel `NewMessage/UpdateMessage/RemoveMessage` ne sont envoyés qu'aux users dont `IsOnline` est vrai en base, or `OnDisconnectedAsync` met `IsOnline=false` à la fermeture de n'importe quelle connexion. - Preuve : sortie de `scripts/friends/ui8.py` ("A view after B closes tab2: ... Offline", "B tab1 got message live: False"). - Cause probable : `backend/API/KeepGroupedHub.cs:19` et `:51` (booléen unique au lieu d'un compteur de connexions) ; `Channels/Messages/Create/CreateMessageCommand.cs:49` (filtre `IsOnline` inutile : `Clients.User(...)` suffit). Côté client, `frontend/src/routes/dashboard.tsx:38-41` (`handleUnload` envoie Offline sans tenir compte des autres onglets). </details> <details><summary>[PROFILE-15] Présence : fermer UN onglet d'un user connecté dans plusieurs onglets le fait passer "Offline" pour tous les autres — Gravité : Mineur</summary> - Où : Accueil > panneau Members (autre session), temps réel SignalR - Étapes : 1. User A connecté dans l'onglet 1 (visible) ; user B voit A dans "ONLINE". 2. A ouvre un 2e onglet (B voit toujours A "ONLINE"), puis le ferme. - Attendu : A reste "Online" (l'onglet 1 est toujours ouvert et visible). - Obtenu : B voit A passer dans "OFFLINE" (3 s après) et il y reste, même après un `bring_to_front` de l'onglet 1 ; seul un changement de visibilité ou un reload de A le corrigera. - Preuve : sortie de script (`B sees A: OFFLINE — 64` après fermeture du 2e onglet). - Cause probable : `frontend/src/routes/dashboard.tsx:38-44` (`handleUnload` envoie `setSelfActivity(Offline)` à chaque onglet) ; l'état de présence est purement client (`activity.hook.ts`), aucun comptage de connexions par user côté hub (`backend/API/KeepGroupedHub.cs`). </details> <details><summary>[FRIENDS-15] Présence figée après une déconnexion abrupte (le serveur ne diffuse pas "Offline") — Gravité : Mineur</summary> - Où : `ActivityLabel` / onglet "Online" / `ProfilePic` status ; hub `OnDisconnectedAsync` - Étapes : 1. A sur `/messages/online`, B (ami) en ligne. 2. B ferme brutalement sa page (`page.close()` sans `beforeunload`, équivalent crash / coupure réseau / mobile). 3. Attendre 12 s. - Attendu : B disparaît de "Online" chez A. - Obtenu : B reste dans "ONLINE — 1" avec le statut "Away" (dernier `visibilitychange`) indéfiniment ; il faut recharger la page de A pour qu'il disparaisse. La présence ne repose que sur des événements envoyés par le client (`routes/dashboard.tsx` `beforeunload`) ; `KeepGroupedHub.OnDisconnectedAsync` ne notifie personne. - Preuve : sortie de `scripts/friends/ui9.py` ("A online tab after B abrupt close (4s): ... Away", idem à +12 s, vide après reload). - Cause probable : `backend/API/KeepGroupedHub.cs:44-54` (pas de `Clients.Others.SendAsync("OtherActivityUpdated", userId, Offline)`). </details> <details><summary>[PROFILE-16] Présence : après une déconnexion brutale (crash navigateur/onglet tué/réseau coupé) le user reste affiché "Away/Online" indéfiniment pour les autres — Gravité : Mineur</summary> - Où : Accueil > Members, compteur "x/y Online" - Étapes : 1. A et B connectés. 2. Fermer le contexte de A sans `beforeunload` (kill du navigateur). 3. Observer B pendant 15 s, puis recharger B. - Attendu : A passe "Offline" pour B quand la connexion SignalR de A tombe. - Obtenu : B voit A "AWAY — 3" (dernier état connu) au-delà de 15 s ; après un reload de B, A apparaît "OFFLINE". `OnDisconnectedAsync` met `IsOnline=false` en base mais ne diffuse rien aux autres clients ; `IsOnline` n'est lu nulle part. - Cause probable : `backend/API/KeepGroupedHub.cs:41-54` (pas de `Clients.Others.SendAsync("OtherActivityUpdated", userId, Offline)` dans `OnDisconnectedAsync`). - Note : fermeture normale d'un onglet unique, bascule onglet masqué -> "Away" (immédiate), retour -> "Online", late-joiner (AskOthersActivity) fonctionnent correctement. </details> --- _Trouvé par une campagne de tests QA automatisés (agents Claude, Playwright) sur l'environnement de dev. Les captures citées sont locales et non jointes._
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
Transcendence/backend#99
No description provided.