feat(enakgame): filter play history by game and status

GET /customer/enakgame/sessions takes optional game_id and status, so a game
reloaded mid-play finds the session it was running (status=STARTED) instead
of starting a new one and charging EnakCoin again. An invalid game_id or
status is refused.

integration-enakgame.md §4.4 now describes recovery after a reload: keep the
session_id in sessionStorage, continue a STARTED session before expires_at,
and call complete again for a COMPLETED one to get the full answer, prize
included. The mobile guide and RFC §11 mention the filters.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
efrilm
2026-10-08 12:51:39 +07:00
co-authored by Claude Opus 5.5
parent b5d2cd491a
commit 52e8fe11c6
10 changed files with 129 additions and 24 deletions
+24 -2
View File
@@ -675,12 +675,34 @@ func TestGameSession_CustomerReads(t *testing.T) {
_, err = e.sessions.GetSession(ctx, e.bob, started.SessionID)
assert.ErrorIs(t, err, repository.ErrGameSessionNotFound, "another customer's session")
page, err := e.sessions.ListSessions(ctx, e.alice, 1, 10)
page, err := e.sessions.ListSessions(ctx, e.alice, models.GameSessionListQuery{Page: 1, Limit: 10})
require.NoError(t, err)
assert.EqualValues(t, 1, page.Pagination.Total)
page, err = e.sessions.ListSessions(ctx, e.bob, 1, 10)
page, err = e.sessions.ListSessions(ctx, e.bob, models.GameSessionListQuery{Page: 1, Limit: 10})
require.NoError(t, err)
assert.Empty(t, page.Data)
// After a reload, the game finds the play it was running by game and status.
other := e.playableGame(e.orgA, "other", 1)
otherStarted, err := e.sessions.Start(ctx, e.alice, other.ID, "k2")
require.NoError(t, err)
_, err = e.sessions.Complete(ctx, e.alice, otherStarted.SessionID, models.GameSessionCompleteInput{})
require.NoError(t, err)
running, err := e.sessions.ListSessions(ctx, e.alice, models.GameSessionListQuery{GameID: game.ID.String(), Status: "started"})
require.NoError(t, err)
require.Len(t, running.Data, 1)
assert.Equal(t, started.SessionID, running.Data[0].ID)
running, err = e.sessions.ListSessions(ctx, e.alice, models.GameSessionListQuery{GameID: other.ID.String(), Status: constants.GameSessionStatusStarted})
require.NoError(t, err)
assert.Empty(t, running.Data, "the other game's play is completed")
all, err := e.sessions.ListSessions(ctx, e.alice, models.GameSessionListQuery{})
require.NoError(t, err)
assert.EqualValues(t, 2, all.Pagination.Total)
_, err = e.sessions.ListSessions(ctx, e.alice, models.GameSessionListQuery{Status: "PLAYING"})
assert.ErrorIs(t, err, ErrGameSessionRejected)
_, err = e.sessions.ListSessions(ctx, e.alice, models.GameSessionListQuery{GameID: "runner"})
assert.ErrorIs(t, err, ErrGameSessionRejected)
}
// gameWith makes an ACTIVE game of org A with the given result rules and an active