Skip to content

feat: implement The Last of Guss — fullstack clicker game with race-condition-safe tap processing#1

Open
Alimjanov-Ibragim wants to merge 4 commits into
r-nep-kz:mainfrom
Alimjanov-Ibragim:test-task
Open

feat: implement The Last of Guss — fullstack clicker game with race-condition-safe tap processing#1
Alimjanov-Ibragim wants to merge 4 commits into
r-nep-kz:mainfrom
Alimjanov-Ibragim:test-task

Conversation

@Alimjanov-Ibragim

Copy link
Copy Markdown

Overview

Full implementation of the clicker game assignment. The existing skeleton had
architectural gaps and bugs that were fixed alongside the feature work.


What was implemented

Shared contract (contract/)

  • Defined strict TypeScript types for all API request/response shapes
  • Added computeRoundStatus(start, end, now) — single source of truth for
    round status, shared between server and client. Status is never stored in DB,
    always derived from timestamps
  • Added computeScoreFromTaps(taps) — score formula encapsulated in one place:
    1 tap = 1 point, every 11th tap = 10 points

Backend (server/)

  • Auth: validateOrCreate flow — registers new users on first login,
    validates existing ones via bcrypt. Role assigned by username at registration
    (admin → admin, Никита → nikita, others → user)
  • JWT: stateless, role embedded in payload — no DB lookup per request.
    AuthGuard('jwt') applied at class level on GamesController
  • Tap processing: wrapped in READ_COMMITTED transaction with
    SELECT FOR UPDATE on the score row — prevents lost updates under
    concurrent requests from the same user
  • Nikita rule: tap returns HTTP 200 but taps counter is not incremented,
    so score stays 0
  • Round status: computed from start_datetime / end_datetime on every
    read — no background jobs, no status desync
  • Round summary: totalScore and bestPlayer computed from all scores
    on demand when round is finished

Frontend (client/)

  • Auth page, rounds list (home), round page — all three states:
    cooldown countdown, active tapping, finished results
  • Goose image switches between guss_ready, guss_tapped, guss_stop
    based on round state and tap animation
  • Score updates optimistically from tap response without full page reload
  • Auto-reload on round finish to fetch final results from server

Infrastructure

  • docker-compose.yml for PostgreSQL 16
  • server/.env.example with all required variables documented

Key design decisions

Decision Rationale
Computed round status Eliminates background jobs and stored-status desync
SELECT FOR UPDATE Prevents race conditions on concurrent taps
Role in JWT payload Stateless role checks without DB roundtrip per request
Shared contract package One place for types and business logic formulas
UUID for rounds Safe to expose in URLs, no sequential ID enumeration

How to run

docker compose up -d
cp server/.env.example server/.env

cd contract && npm install && npm run build
cd ../server && npm install && npm run start
cd ../client && npm install && npm run dev

…ssing

- Fix contract types: computed RoundStatus, proper response shapes, roundUuid field
- Fix auth: add role mapping (admin/nikita/user), validateOrCreate flow
- Fix games: transaction + SELECT FOR UPDATE for tap processing, computed round status
- Fix Nikita rule: tap accepted but counter not incremented
- Fix client: remove debug text, match mockups, proper countdown and score display
- Remove dead code, unused imports, strict TypeScript compliance
- Translate all comments to English
- Add docker-compose.yml for PostgreSQL 16 on port 6543
- Add server/.env.example as environment template
- Add root .gitignore (node_modules, dist, .env)
- Complete rewrite: tech stack, architecture decisions, quick start guide
- Document all environment variables with defaults
- Add test credentials table (admin, player, nikita roles)
- List API endpoints with auth requirements
Restore original assignment text at the top of README.
Add detailed answers to all four questions based on real project experience.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant