Band Name Validation
Every submitted band name goes through four checks in order. Failing any check ends the game immediately — the submitting player loses.
Validation Order
1. Not Empty
The band name, after trimming whitespace, must have a non-zero length.
Error: "Band name cannot be empty"
2. Duplicate Detection
The same band cannot be played twice in the same match.
Normalisation rule: strip a leading "The " (case-insensitive) and lowercase the remainder before comparing.
text
"The Beatles" → "beatles"
"Beatles" → "beatles" ← same, rejected
"BEATLES" → "beatles" ← same, rejected
"Metallica" → "metallica"Only moves with moveType = 'playBand' and valid = true in the current match are checked.
Error: "Band name already used in this game"
3. Spotify Lookup
Handled by SpotifyService.validateBand().
Search
Calls GET /v1/search with:
q: the submitted band nametype:artistlimit: 5 results
Name Matching (case-insensitive)
The service checks results against three forms of the submitted name:
| If input… | Also checks |
|---|---|
Does NOT start with "the " | "the " + input |
DOES start with "the " | input without the leading "the " |
A result matches if artist.name equals any of the above variants (case-insensitive).
Follower Threshold
Matched artist must have followers.total >= 500.
Error (not found): "No band with the name \"{bandName}\" found on Spotify."
Error (too few followers): "Band has too few followers ({count}). Minimum required: 500."
Error (API failure): "Failed to validate band with Spotify API"
Canonical Name
The Spotify artist name is used as the canonical band name — not what the player typed.
text
Player types: "beatles"
Spotify finds: "The Beatles"
Stored as: { bandName: "The Beatles", submitted: "beatles" }The submitted field is only stored when it differs from the canonical name. All downstream checks (letter chain, duplicate detection) use the canonical name.
Token Management
- Uses Spotify client credentials flow (no user login needed)
- Token cached in memory with expiry; auto-refreshed when stale
- Requires env vars:
SPOTIFY_CLIENT_ID,SPOTIFY_CLIENT_SECRET
4. Letter-Chain Rule
Each band name must start with the last letter of the previous canonical band name.
"The" Handling
The word "The" at the start of a band name is treated as a prefix, not part of the effective name for letter-chain purposes.
- Starting letter: first letter of the word after "The"
- Ending letter: last letter of the full canonical name (including "The" bands — last letter of the last word)
text
"The Cardigans" → effective start = 'C', end = 'S'
"The Stooges" → effective start = 'S', end = 'S'
"Slayer" → effective start = 'S', end = 'R'Special Case: Previous Band Ends with 'T'
If the previous band name ends with the letter 'T', any band starting with "The" is also valid, because the T in "The" satisfies the chain.
text
Previous: "Warrant" (ends R) → next must start with R
Previous: "Accept" (ends T) → next can start with T OR be any "The X" bandFirst Move
The first band in any game always passes the letter-chain check (no previous band to match against).
Move Response Shapes
Valid move:
json
{ "success": true, "gameState": { "..." } }Invalid move (game ends, player loses):
json
{
"success": false,
"illegal": true,
"reason": "No band with the name \"Bnad\" found on Spotify.",
"gameState": { "...with move recorded as invalid..." }
}Rejected move (not recorded, game continues):
json
{
"success": false,
"error": "Not your turn"
}Move rejections (not your turn, game not active, player not in game) do not end the game and do not record the move. Only invalid band submissions end the game.