Enforce unique team names within a season #49

Merged
chrisp merged 1 commit from fix/team-name-uniqueness into main 2026-05-24 00:07:29 +00:00
Owner

Summary

  • Add `findTeamByNameInSeason` to the team model using `lower()` for exact case-insensitive matching (avoids SQL `LIKE` wildcard injection that `ilike` would have allowed)
  • Validate uniqueness in the user-facing team settings rename action
  • Validate uniqueness in admin assign-owner and remove-owner paths that auto-generate names from owner usernames
  • Reject whitespace-only names that would trim to an empty string
  • Add DB-level `UNIQUE INDEX ON teams (season_id, lower(name))` (migration `0113_bent_banshee`) to close the TOCTOU race and enforce the constraint at the database layer regardless of code path

Test plan

  • Rename a team to an existing team name in the same season — should be rejected
  • Rename a team to the same name with different casing — should be rejected
  • Rename a team to its own current name — should succeed (self excluded from check)
  • Submit a whitespace-only team name — should be rejected
  • Admin: assign an owner whose auto-generated name would collide — should be rejected
  • Admin: remove an owner whose stripped name would collide — should be rejected
  • Run `npm run db:migrate` and confirm migration applies cleanly

🤖 Generated with Claude Code

## Summary - Add \`findTeamByNameInSeason\` to the team model using \`lower()\` for exact case-insensitive matching (avoids SQL \`LIKE\` wildcard injection that \`ilike\` would have allowed) - Validate uniqueness in the user-facing team settings rename action - Validate uniqueness in admin assign-owner and remove-owner paths that auto-generate names from owner usernames - Reject whitespace-only names that would trim to an empty string - Add DB-level \`UNIQUE INDEX ON teams (season_id, lower(name))\` (migration \`0113_bent_banshee\`) to close the TOCTOU race and enforce the constraint at the database layer regardless of code path ## Test plan - [ ] Rename a team to an existing team name in the same season — should be rejected - [ ] Rename a team to the same name with different casing — should be rejected - [ ] Rename a team to its own current name — should succeed (self excluded from check) - [ ] Submit a whitespace-only team name — should be rejected - [ ] Admin: assign an owner whose auto-generated name would collide — should be rejected - [ ] Admin: remove an owner whose stripped name would collide — should be rejected - [ ] Run \`npm run db:migrate\` and confirm migration applies cleanly 🤖 Generated with [Claude Code](https://claude.com/claude-code)
chrisp added 1 commit 2026-05-23 23:55:32 +00:00
Enforce unique team names within a season
All checks were successful
🚀 Deploy / 🧪 Test (pull_request) Successful in 1m31s
🚀 Deploy / ʦ TypeScript (pull_request) Successful in 1m19s
🚀 Deploy / 🔍 Lint (pull_request) Successful in 48s
🚀 Deploy / 🐳 Build (pull_request) Has been skipped
🚀 Deploy / 🚀 Deploy (pull_request) Has been skipped
c9fdb12a09
- Add findTeamByNameInSeason (exact case-insensitive match via lower()) to the team model
- Validate uniqueness in the user-facing team settings rename action
- Validate uniqueness in admin assign-owner and remove-owner paths that auto-generate names
- Reject whitespace-only team names that would trim to an empty string
- Add DB-level unique index on (season_id, lower(name)) to close the TOCTOU race

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
chrisp merged commit 3518bd77e8 into main 2026-05-24 00:07:29 +00:00
Sign in to join this conversation.
No description provided.