fix(room): enforce single membership and explicit room closure (#2) #26

Merged
Reliodas merged 1 commit from fix/2-room-lifecycle into develop 2026-06-22 23:34:43 +00:00
Owner

Implements ticket #2 — secure the room lifecycle and closure.

Problem

A socket could create/join several rooms, leaving old rooms, players and timers dangling; returning home never closed the game explicitly.

Changes

  • Single active membership: room.store.leaveRoom(socketId) closes the room when the host leaves and removes the candidate immediately otherwise (cancelling any pending grace). room:create/room:join first detach the socket from any previous room, so no orphan room or timer survives.
  • Explicit closure: new room:leave event (distinct from the grace-delayed disconnection). Host leave → others get room:closed; player leave → host sees the candidate gone. closeRoom stops the game timer and all of the room's grace timers.
  • Client: useSocket.leave() emits room:leave, clears the stored session and resets state; a reusable QuitButton ("Quitter" / "Fermer la salle") is wired into the host, player and spectator views and returns home.
  • Additive socket contract (room:leave).

Verification (local, all green)

  • Server node:test 89 pass / 1 skip (new lifecycle + leaveRoom + single-membership tests)
  • Server Jest 9 pass; c8 coverage 81.8 / 78.8 / 87.7 / 81.8 — above floors
  • Client Vitest 42 pass (new QuitButton test + useSocket leave test); coverage above floors and improved
  • Client production build OK
  • Playwright e2e 3 pass (incl. host closes the room)
  • Typechecks clean across shared/server/client

Docs updated: docs/Implémentation.md (events, lifecycle, tests, limits) and docs/Regles.md.

Refs #2

Implements ticket #2 — secure the room lifecycle and closure. ## Problem A socket could create/join several rooms, leaving old rooms, players and timers dangling; returning home never closed the game explicitly. ## Changes - **Single active membership**: `room.store.leaveRoom(socketId)` closes the room when the host leaves and removes the candidate immediately otherwise (cancelling any pending grace). `room:create`/`room:join` first detach the socket from any previous room, so no orphan room or timer survives. - **Explicit closure**: new `room:leave` event (distinct from the grace-delayed disconnection). Host leave → others get `room:closed`; player leave → host sees the candidate gone. `closeRoom` stops the game timer and all of the room's grace timers. - **Client**: `useSocket.leave()` emits `room:leave`, clears the stored session and resets state; a reusable `QuitButton` ("Quitter" / "Fermer la salle") is wired into the host, player and spectator views and returns home. - Additive socket contract (`room:leave`). ## Verification (local, all green) - Server `node:test` 89 pass / 1 skip (new lifecycle + leaveRoom + single-membership tests) - Server Jest 9 pass; c8 coverage 81.8 / 78.8 / 87.7 / 81.8 — above floors - Client Vitest 42 pass (new QuitButton test + useSocket leave test); coverage above floors and improved - Client production build OK - Playwright e2e 3 pass (incl. host closes the room) - Typechecks clean across shared/server/client Docs updated: `docs/Implémentation.md` (events, lifecycle, tests, limits) and `docs/Regles.md`. Refs #2
fix(room): enforce single membership and explicit room closure
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
ci/woodpecker/pr/woodpecker Pipeline was successful
ci/woodpecker/pull_request_closed/woodpecker Pipeline was successful
621517c984
A socket could create or join several rooms, leaving old rooms, players
and timers dangling, and returning to the home screen never closed the
game. Add an intentional, immediate departure path distinct from the
grace-delayed disconnection.

- room.store: leaveRoom(socketId) closes the room when the host leaves and
  removes the candidate immediately otherwise (cancelling any pending grace),
  guaranteeing a socket holds at most one active membership.
- room.handler: new room:leave event; room:create and room:join first detach
  the socket from any previous room, so no orphan room or timer survives.
  closeRoom stops the game timer and all of the room's grace timers.
- client: useSocket.leave() emits room:leave, clears the stored session and
  resets state; a reusable QuitButton ("Quitter" / "Fermer la salle") wired
  into the host, player and spectator views returns home.

Covered by room.store unit tests (leave + single membership), Socket.IO
integration scenarios (explicit close, candidate leave, successive create
cleanup), a useSocket leave test, a QuitButton component test and a Playwright
close-room journey. Docs updated.

Refs #2

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Reliodas merged commit 06b5959f61 into develop 2026-06-22 23:34:43 +00:00
Sign in to join this conversation.
No reviewers
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: jeux/le-grand-concours#26
No description provided.