feat(games): open and join games - #200
Open
Utzig26 wants to merge 1 commit into
Open
Conversation
Implements RFC-002. Brings back the module that carried the reason for the API to exist, with the state machine, the readable id and the two routes that put players on a board. POST /games opens a game in WP with the creator on the colour they asked for, or on one drawn at random. POST /games/:id/join takes the open colour and moves the game to W. Playing yourself is supported rather than tolerated: the creator may join their own game, hold both colours, and later move each side in turn. It is documented in Swagger and covered by a test. The readable id keeps the shape the old code used, but inverts the control. The old loop queried the collection until it found a free id; this generates one, tries to insert, and lets the unique index reject it, retrying up to five times. Same lesson as the duplicate username: the index decides, and it decides atomically. The player id never leaves the service. Responses carry only the username, which is what the old code achieved with a Transform on serialisation, and two end-to-end tests assert no twenty-four character hex string appears in any response body. The initial FEN is complete now. The old schema defaulted to the piece placement alone, so a client trusting it before the first move parsed an invalid string. Spelling in the public contract is fixed rather than inherited: additionalInfo, and "Waiting for the players to connect". Two defects the tests caught, both recorded in the RFC because they will bite again: ValidateNested does not require presence. A body with no timeControl passed validation and crashed the service on destructuring. It needs IsObject alongside it. A mongoose field cannot be required and default to an empty string at the same time, since mongoose reads the empty string as missing. A new game failed its own schema validation on pgn. 17 unit tests over colour selection, id collisions and every state that refuses a join, and 24 end-to-end covering the envelope, the time control matrix, self-play and the id leak.
This was referenced Jul 31, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Implements RFC-002. Brings back the module that carried the reason for the API to exist.
What lands
POST /gamesWP, creator takes one colourPOST /games/:id/joinWThe state machine (
WP → W → A → F), the game schema, the readable id, and the serializer that will be shared with RFC-006 and RFC-007.Playing yourself is supported, not tolerated
The creator may join their own game, hold both colours, and later move each side in turn. In the old code this worked by omission — nobody checked who was joining, and
wichPlayer()already returned'wb'for the case without anything documenting it. Here it is in the Swagger description and covered by a test.The unique index decides the id
The old loop queried the collection until it found a free
resourceId. This generates one, tries to insert, and lets the unique index reject it, retrying up to five times before giving up with a 500.Same lesson as the duplicate username in #198: the index decides, and it decides atomically.
The player id never leaves the service
Responses carry only the username, which is what the old code achieved with a
@Transformon serialisation. Two end-to-end tests assert that no twenty-four character hex string appears in any response body.Other corrections carried over from the legacy notes
The initial FEN is complete (
... w KQkq - 0 1). The old schema defaulted to the piece placement alone, so a client trusting it before the first move parsed an invalid string.Spelling in the public contract is fixed rather than inherited:
additionalInfo, and"Waiting for the players to connect".Two defects the tests caught
Both are recorded in the RFC, because they will bite again in RFC-003 and RFC-005.
@ValidateNested()does not require presence. A body with notimeControlpassed validation and crashed the service on destructuring. It needs@IsObject()alongside it. Caught byrejects a missing time control.A mongoose field cannot be
requiredand default to''at the same time, since mongoose reads the empty string as missing. A new game failed its own schema validation onpgn.The engine boundary caught the test suite
The
no-restricted-importsrule added in #199 fired ontest/games.e2e-spec.ts, which had importedchess.jsto assert the FEN parses. The import was dropped rather than the rule relaxed — the exact string assertion already proves the FEN is complete, andchess-engine.service.specalready proves it parses.Verification
181 tests green, clean
stricttypecheck and lint.