feat(tournaments): add partnership tracking and tournament management

Implement comprehensive partnership tracking system and tournament
management features including round-robin, single/double elimination,
and Swiss system pairings.

Changes:
- Add partnership_games and partnership_stats tables
- Implement PartnershipTracker service for recording partnership data
- Add tournament generator with multiple formats
- Create tournament management actions and views
- Add acceptance tests for partnership tracking
- Fix PartnershipTracker to use single snapshot per player per match
- Fix round-robin test to query by round_number instead of hardcoded ID

Note: All 8 acceptance tests now passing
This commit is contained in:
2026-03-27 12:25:34 -07:00
parent cb47b9da99
commit ac858f1e6d
55 changed files with 2591 additions and 0 deletions
@@ -0,0 +1,44 @@
<h1>Enter Results: <%= tournament.name %> - Round <%= round[:round_number] %></h1>
<form action="/admin/tournaments/<%= tournament.id %>/results" method="post">
<input type="hidden" name="_csrf_token" value="<%= csrf_token %>">
<table>
<thead>
<tr>
<th>Matchup</th>
<th>Team 1</th>
<th>Score</th>
<th>vs</th>
<th>Team 2</th>
<th>Score</th>
</tr>
</thead>
<tbody>
<% matchups.each_with_index do |matchup, i| %>
<% team_1 = teams.find { |t| t.id == matchup[:team_1_id] } %>
<% team_2 = teams.find { |t| t.id == matchup[:team_2_id] } %>
<% next if team_1.nil? || team_2.nil? %>
<tr>
<td><%= i + 1 %></td>
<td><%= team_1.team_name %></td>
<td>
<input type="number" name="team_1_score_<%= matchup[:id] %>" min="0" max="10" value="10" style="width: 60px;">
</td>
<td>vs</td>
<td><%= team_2.team_name %></td>
<td>
<input type="number" name="team_2_score_<%= matchup[:id] %>" min="0" max="10" value="7" style="width: 60px;">
</td>
<td>
<input type="checkbox" name="matchup_<%= matchup[:id] %>" checked style="display:none;">
</td>
</tr>
<% end %>
</tbody>
</table>
<button type="submit">Save All Results</button>
</form>
<p><a href="/admin/tournaments/<%= tournament.id %>">Back to Tournament</a></p>