SquadImporter¶
Imports squad rosters (team-by-season player, coach, and staff lists) from the foundry.squads ClickHouse table into the SquadAggregate. Resolves provider IDs to LuckBox canonical IDs, groups rows by team and season, and reconciles each squad declaratively so the read model matches the feed exactly.
This importer is driven automatically by SquadImportTimerService, which polls hourly for AmericanFootball/ESPN. It can also be triggered on demand via the import API.
Importer Details¶
| Property | Value |
|---|---|
| Importer Name | Squad |
| Data Contract | SquadImportData |
| Module | LBS.Sport.Integration |
| Authorization | Requires ContentManager role (same as the squad commands it issues) |
| Commands Generated | CreateSquadCommand, SetSquadListCommand (one of each per team/season group) |
| Event Raised | SquadCreated, SquadListAdded (and reconcile events: SquadMemberAdded, SquadMemberRemoved, SquadMemberTierUpdated, SquadMemberJerseyUpdated, SquadMemberPositionUpdated) |
Input Contract¶
| Field | Type | Required | Description |
|---|---|---|---|
Sport |
Sport |
Yes | The sport to import squads for e.g. AmericanFootball |
DataProvider |
DataProvider |
Yes | The provider feed to read e.g. ESPN |
Behaviour¶
- Reads all squad rows from the
foundry.squadsClickHouse table for the requested sport and provider - For each row, resolves the canonical LuckBox IDs via
IEntityMappingService: team_provider_id-> canonicalTeamIdparticipant_provider_id-> canonicalParticipantIdseason_provider_id(a composite"competitionId/year") -> canonicalSeasonId- Skips any row whose team, participant, or season cannot be resolved, logging a warning (a bare year with no competition prefix is treated as unresolvable and skipped)
- Maps the row fields onto squad member attributes:
squad_tier->NflSquadTiers.*- position abbreviation ->
Positions.AmericanFootball.*(viaMapPosition) - jersey string ->
int - Groups the surviving rows by
(team_provider_id, season_provider_id)— one group per squad - For each group, emits exactly two commands:
CreateSquadCommand- ensures theSquadAggregateexists for the deterministicSquadId.From(SeasonId, TeamId)SetSquadListCommand- submits the full resolved roster for declarative reconciliationSetSquadListCommandreconciles the roster against the current squad state: new members are added, omitted members are removed, and changed members (tier, jersey, position) are updated. The operation is idempotent, so re-running the importer against an unchanged feed produces no further events.
ID Resolution Chain¶
foundry.squads row (provider IDs)
-> IEntityMappingService
-> TeamId (from team_provider_id)
-> ParticipantId (from participant_provider_id)
-> SeasonId (from season_provider_id == "competitionId/year")
-> grouped by (TeamId, SeasonId)
-> SquadId.From(SeasonId, TeamId)
Rows with any unresolved canonical ID are skipped and logged; a season_provider_id that is a bare year (no competitionId/ prefix) cannot be resolved and is skipped.
Related Files¶
| File | Description |
|---|---|
src/Integration/LBS.Sport.Integration/Importers/Squad/SquadImporter.cs |
Importer implementation |
src/Integration/LBS.Sport.Integration/Importers/Squad/SquadImportTimerService.cs |
Automated hourly polling service (AmericanFootball/ESPN) |
src/Domain/LBS.Domain.Sport/Squad/Command/CreateSquadCommand.cs |
Domain command that creates the squad aggregate |
src/Domain/LBS.Domain.Sport/Squad/Command/SetSquadListCommand.cs |
Domain command that reconciles the full roster |
src/Domain/LBS.Domain.Sport/Squad/SquadAggregate.cs |
Aggregate handler and validation |
src/Domain/LBS.Domain.Sport/Squad/SquadContractBuilder.cs |
Async projection that builds SquadContract |