Repository navigation
feat(games): add game status pills and personal score on the game page - #55
Merged
Merged
Conversation
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…y a scored game The set_game_status and remove_game rows were cast to hand written shapes, so a renamed SQL column compiled and the Undo silently disappeared. They now widen the generated row, which keeps a rename a compile error. Clearing a score now matches only a scored row: any update moves updated_at, which restore_game_status measures its 10 minute window from, so a stale tab could extend an old Undo. The spec now lists five functions and the restore parameters in the migration's order. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Adds tests for the actions, the status control and tracking slot, the game state read, the release helpers, and the game cases of the schemas, messages and error classification. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Ticks the verify steps that ran, marks Verify, Test and Review done for G4 in the games scope, and adds the fresh model review findings. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ating Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Moves the session, catalog check, write, classify and refresh order out of app/movies/actions.ts into lib/tracking/write.ts, so the game actions can use the same copy instead of repeating it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The game actions now use runTrackingWrite and parseTrackingInput, read the prev_* and removed_* columns through one readRestoreState, and call the hidden-inclusive read readGameIncludingHidden so its name says what it does. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e place GAME_STATUSES comes from the generated enum, so the Zod schema follows SQL, and canHoldScore is the one TypeScript copy of "only Playing or Finished holds a score". The game input schemas get their doc lines. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The control reads GAME_STATUSES and canHoldScore, both toast sites name the failure toast through gameTrackingToastId, showRestored replaces the restoring thunk factory, and the release gate cites AGENTS.md Games. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Names readGameIncludingHidden as the IGDB read, records the rating is not null filter on a cleared score and why, states that a hidden game can be scored, and describes the status pills as a fieldset. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This branch was successfully deployed
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.
What
Signed in users can now set a game's status on
/games/{id}(Want to play, Playing, Finished) and give it a personal score from 1 to 10. Clicking the pill that is already on removes the game. Removing a game, or losing a score by moving back to Want to play, shows a toast with Undo.Why
Implements spec 0026, scope feature G4 in docs/scope/games.md. It builds on the
user_game_statetable from spec 0024 and the game page from spec 0025. Options and reasoning are in rationale.md.Changes
20261024120000_game_tracking_functions.sqladds fivesecurity invokerfunctions:set_game_status,rate_game,remove_game,restore_game_statusandrestore_removed_game. Each is granted toauthenticatedonly and writesauth.uid()itself, so RLS still applies.set_game_statuslocks the row before it reads the old values, so two tabs never get the same Undo payload. The restores refuse (P0002) outside a 10 minute window. A score on a game with no row, or on Want to play, is refused with a new code,BS004. There is no new table or column.app/games/actions.ts):setGameStatus,setGameRating,removeGame,restoreGameStatusandrestoreRemovedGame. They share one order: Zod parse, then the session check, then the IGDB check and the release check, then the write under the user's JWT, thenrefresh(). None of them throws or redirects. IGDB is only called when a write could move a game forward. Removing, clearing a score and both restores skip IGDB, so they still work during an IGDB outage, on a hidden game, or before release. Clearing a score only touches a row that has a score.not_released. A pressed pill on an unreleased game can still be clicked to remove it.GameTrackingSlotandGameStatusControlgo in the hero's tracking slot, shaped like the movie pills. The control updates optimistically throughuseOptimisticand the pure reducerapplyGameIntent. Moving into Finished opens the score picker when the game has no score yet. Failures roll back and show the matching toast, including a session expired toast with Sign in. Visitors see nothing in the slot, and the page shell stays prerendered.classifyGameTrackingError) andgame_tracking.*log events inlib/tracking/. The release helpers live inlib/catalog/game-page.ts.190-game-tracking-functionsand new grant checks in020-security-configuration. Vitest covers the actions, the reducer, schemas, errors, the control, the slot and the release helpers. Every new action is registered inprivate-actions-boundary.test.ts.How to test / verify
supabase db reset, thenpnpm dev:docker. Sign in asuser-a@example.test. The seed has 1942 as Playing with score 8./games/1942. The pills show Playing pressed with score8, and the state doesn't flicker on load.Releases {date}orRelease date to be announced, and Playing and Finished are disabled.pnpm test:db,pnpm db:types:check,pnpm typecheck,pnpm lint,pnpm testandpnpm build. The full manual list is in verify.md, and every step is checked off there.Risk & rollout
supabase db push, as docs/deploy.md asks before merge./games/{id}directly sees this.60e1de9: Undo rows are typed from the generated types, clearing only touches a scored row, and the spec now matches the migration. Two nits are open on purpose: a comment on why opening the picker outside the transition is safe, and a separate log outcome for errors inreadGamethat don't come from IGDB.Notes for reviewers
set_game_status, and howbestats.restore_gameis turned back off on every path, including before a raise (the migration).requestTodayUtc(), and the action usestodayUtc(new Date()). Around UTC midnight they can disagree, so an enabled pill can still returnnot_released. The spec accepts this (AC-9).🤖 Generated with Claude Code