Skip to content

Carambus API Database Design Documentation

Core Models and Their Relationships

Seeding Model - Dual Purpose Design

The Seeding model serves two distinct purposes in the system:

  1. Team Roster Management
  2. Connected to LeagueTeam via league_team_id
  3. Used to maintain the full roster of players for a league team
  4. Created during initial league/team setup and scraping
  5. Example: Seeding.where(league_team: league_team, player: player)

  6. Match Participation Tracking

  7. Connected to Party via polymorphic tournament_id and tournament_type
  8. Tracks which players participate in specific matches
  9. Created when setting up individual matches
  10. Example: party.seedings.where("id > #{Game::MIN_ID}")
class Seeding < ApplicationRecord
  belongs_to :player, optional: true
  belongs_to :tournament, polymorphic: true, optional: true
  belongs_to :league_team, optional: true
  # ...
end

Party and LeagueTeam Relationship

The relationship between Party and LeagueTeam is designed to handle match scheduling and team participation:

class Party < ApplicationRecord
  belongs_to :league_team_a, class_name: "LeagueTeam"
  belongs_to :league_team_b, class_name: "LeagueTeam"
  belongs_to :host_league_team, class_name: "LeagueTeam"
  belongs_to :no_show_team, class_name: "LeagueTeam"
  has_many :seedings, as: :tournament
  # ...
end

class LeagueTeam < ApplicationRecord
  has_many :parties_a, class_name: "Party", foreign_key: :league_team_a_id
  has_many :parties_b, class_name: "Party", foreign_key: :league_team_b_id
  has_many :parties_as_host, class_name: "Party", foreign_key: :host_league_team_id
  has_many :no_show_parties, class_name: "Party", foreign_key: :no_show_team_id
  has_many :seedings
  # ...
end

Data Storage Patterns

Flexible Data Storage

Several models use serialized columns for flexible data storage:

  1. JSON Serialization
    serialize :data, coder: JSON, type: Hash
    
    Used in:
  2. Party - Stores match-specific data
  3. Seeding - Stores player results and rankings
  4. LeagueTeam - Stores team-specific metadata

  5. YAML Serialization

    serialize :remarks, coder: YAML, type: Hash
    
    Used in:

  6. Party - Stores match remarks and notes

Region Tagging System

The RegionTaggable concern provides intelligent region handling:

# Example from RegionTaggable
when Seeding
  if tournament_id.present?
    # Handle tournament-based region tagging
    tournament ? [
      tournament.region_id,
      (tournament.organizer_type == "Region" ? tournament.organizer_id : nil),
      find_dbu_region_id_if_global
    ].compact : []
  elsif league_team_id.present?
    # Handle league team-based region tagging
    league_team&.league ? [
      (league_team.league.organizer_type == "Region" ? league_team.league.organizer_id : nil),
      find_dbu_region_id_if_global
    ].compact : []
  end

Data Protection and Synchronization

Local Protection

The LocalProtector concern is used to protect local data from external modifications:

class Party < ApplicationRecord
  include LocalProtector
  # ...
end

class LeagueTeam < ApplicationRecord
  include LocalProtector
  # ...
end

class Seeding < ApplicationRecord
  include LocalProtector
  # ...
end

Source Handling

The SourceHandler concern manages external data synchronization:

class Party < ApplicationRecord
  include SourceHandler
  # ...
end

class LeagueTeam < ApplicationRecord
  include SourceHandler
  # ...
end

Key Workflows

Team Setup and Match Creation

  1. League teams are created with their base roster (seedings with league_team_id)
  2. When a match is created:
  3. A new Party is created linking two LeagueTeams
  4. Specific seedings are created for the match (with tournament_id)
  5. These seedings track which players from the team roster participate in this match

Data Synchronization

  1. External data (from BA/CC) is synchronized through the SourceHandler
  2. Local data is protected from external modifications via LocalProtector
  3. Region tagging is automatically handled based on the context (tournament or league team)

Important Notes for Developers

  1. Seeding Creation
  2. Always consider whether you're creating a team roster entry or a match participation entry
  3. Use appropriate associations (league_team_id vs tournament_id)

  4. Data Protection

  5. Be aware of the LocalProtector when modifying records
  6. Use unprotected = true when necessary for local modifications

  7. Region Handling

  8. Region tagging is automatic but context-dependent
  9. Different logic applies for tournament-based vs league team-based seedings

  10. Data Storage

  11. Use the appropriate serialization (JSON vs YAML) for different types of data
  12. Be aware of the structure of stored data in serialized columns

Database Schema Highlights

Seeding Model

create_table "seedings" do |t|
  t.string "ba_state"
  t.integer "balls_goal"
  t.text "data"
  t.integer "position"
  t.integer "rank"
  t.string "role"
  t.string "state"
  t.string "tournament_type"
  t.integer "league_team_id"
  t.integer "player_id"
  t.integer "playing_discipline_id"
  t.integer "tournament_id"
  # ...
end

Party Model

create_table "parties" do |t|
  t.datetime "date"
  t.integer "league_id"
  t.text "remarks"
  t.integer "league_team_a_id"
  t.integer "league_team_b_id"
  t.integer "host_league_team_id"
  t.integer "no_show_team_id"
  t.text "data"
  # ... other fields ...
end

LeagueTeam Model

create_table "league_teams" do |t|
  t.string "name"
  t.string "shortname"
  t.integer "league_id"
  t.integer "ba_id"
  t.integer "cc_id"
  t.integer "club_id"
  t.text "data"
  # ... other fields ...
end