Add Elo rating system with match entry and CSV upload

- Implement EloCalculator service for 2v2 Euchre matches
- Create background job processing with GoodJob
- Add single match entry form
- Add CSV upload for batch match entry
- Create player rankings view
- Add database schema for matches and elo snapshots
This commit is contained in:
2026-03-26 16:28:24 -07:00
parent 1a9b3496e1
commit 1268889a78
31 changed files with 865 additions and 2 deletions
@@ -0,0 +1,19 @@
# frozen_string_literal: true
module EuchreCamp
module Persistence
module Relations
class EloSnapshots < ROM::Relation[:sql]
schema(:elo_snapshots, infer: true) do
attribute :id, ROM::Types::Integer, primary_key: true
attribute :player_id, ROM::Types::Integer
attribute :match_id, ROM::Types::Integer
attribute :rating_before, ROM::Types::Integer
attribute :rating_after, ROM::Types::Integer
attribute :rating_change, ROM::Types::Integer
attribute :created_at, ROM::Types::DateTime
end
end
end
end
end
@@ -0,0 +1,31 @@
# frozen_string_literal: true
module EuchreCamp
module Persistence
module Relations
class GoodJobs < ROM::Relation[:sql]
schema(:good_jobs, infer: true) do
attribute :id, ROM::Types::Integer
attribute :queue_name, ROM::Types::String
attribute :priority, ROM::Types::Integer
attribute :serialized_params, ROM::Types::String
attribute :scheduled_at, ROM::Types::DateTime.optional
attribute :performed_at, ROM::Types::DateTime.optional
attribute :finished_at, ROM::Types::DateTime.optional
attribute :error, ROM::Types::String.optional
attribute :created_at, ROM::Types::DateTime
attribute :updated_at, ROM::Types::DateTime
attribute :active_job_id, ROM::Types::String.optional
attribute :concurrency_key, ROM::Types::String.optional
attribute :sequence, ROM::Types::Integer.optional
attribute :executions_count, ROM::Types::Integer.optional
attribute :job_class, ROM::Types::String.optional
attribute :error_event, ROM::Types::Integer.optional
attribute :labels, ROM::Types::String.optional
attribute :locked_by_id, ROM::Types::String.optional
attribute :locked_at, ROM::Types::DateTime.optional
end
end
end
end
end
@@ -0,0 +1,29 @@
# frozen_string_literal: true
module EuchreCamp
module Persistence
module Relations
class Matches < ROM::Relation[:sql]
schema(:matches, infer: true) do
attribute :id, ROM::Types::Integer, primary_key: true
attribute :event_id, ROM::Types::Integer.optional
attribute :played_at, ROM::Types::DateTime.optional
attribute :team_1_p1_id, ROM::Types::Integer
attribute :team_1_p2_id, ROM::Types::Integer
attribute :team_2_p1_id, ROM::Types::Integer
attribute :team_2_p2_id, ROM::Types::Integer
attribute :team_1_score, ROM::Types::Integer
attribute :team_2_score, ROM::Types::Integer
attribute :status, ROM::Types::String.default('completed')
associations do
belongs_to :team_1_player, relation: :players, foreign_key: :team_1_p1_id
belongs_to :team_2_player, relation: :players, foreign_key: :team_1_p2_id
belongs_to :team_3_player, relation: :players, foreign_key: :team_2_p1_id
belongs_to :team_4_player, relation: :players, foreign_key: :team_2_p2_id
end
end
end
end
end
end
@@ -1,8 +1,15 @@
# frozen_string_literal: true
module EuchreCamp
module Persistence
module Relations
class Players < ROM::Relation[:sql]
schema(:players, infer: true)
schema(:players, infer: true) do
attribute :id, ROM::Types::Integer, primary_key: true
attribute :name, ROM::Types::String
attribute :rating, ROM::Types::Integer
attribute :current_elo, ROM::Types::Integer.default(1000)
end
end
end
end