You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The schema is a thin slice — players, teams, matches, tournaments — and does not yet
carry the things the product needs: communities, scheduling, formats, money, privacy.
This issue tracks laying down the model, so the feature issues that follow have
something to build on rather than each inventing their own tables.
Scope
Eleven bounded contexts, five migrations that each apply and revert on their own:
Identity — Player (global), PlayerContact with per-channel visibility, PlayerProfile
Privacy — consent records, data requests, media and who appears in it, audit events
Notifications — per-member preferences and a transactional outbox
Decisions
Recorded here because they are expensive to reverse:
Rating lives on CommunityMember, not Player. Standing is relative to the people
you play with.
MatchAppearance is the rating source of truth, not TeamMember. Teams are lineups
and change; who played a given match does not. It also handles substitutes and uneven sides.
Matches snapshot their scoring rules, so amending a rule set cannot rewrite the past.
Money is long minor units plus a currency code. No decimal, no floats.
Double-entry ledger from the start, making dues, fees, expenses and funding one mechanism.
CommunityId is denormalised onto every owned entity; queries filter on it explicitly,
with no global query filter.
Formats carry a rating weight — a 6v6 result says less about one player than a 2v2 does.
Federation is identifiers and a link table only. No protocol yet; the point is that the
schema will not need rewriting when it arrives.
Enforced by the database, not the application
Court reservations cannot overlap (EXCLUDE USING gist, half-open ranges)
Ledger amounts are positive and move between two different accounts
A member-balance account has a member; nothing else does
An item is on loan to at most one person at a time
A community has at most one current season; a format has at most one default rule set
Not in scope here
Left deliberately unbuilt, each wanting its own issue:
Generating Session rows from SessionTemplate (background job)
Draining NotificationOutbox
Writing AuditEvent from a SaveChangesInterceptor
Match confirmation and dispute flow in the UI
Court picker on match entry (free text still lands in LocationNote)
Dashboards are not modelled: they are queries over this schema, not tables. Weather forecasts
are fetched live; only the observation taken at session time is kept.
The schema is a thin slice — players, teams, matches, tournaments — and does not yet
carry the things the product needs: communities, scheduling, formats, money, privacy.
This issue tracks laying down the model, so the feature issues that follow have
something to build on rather than each inventing their own tables.
Scope
Eleven bounded contexts, five migrations that each apply and revert on their own:
Player(global),PlayerContactwith per-channel visibility,PlayerProfileCommunity,CommunityMember,Season, invites, join requests,CommunityLinkVenue,Court,CourtReservationFormat(2v2–6v6, seeded),RuleSet,SessionTemplate,Session,SessionParticipantMatchAppearance,MatchDispute,PlayerFormatStat, tournament entries and bracketsPoll,PollOption,VoteAccount/LedgerEntry, dues, funding sourcesDecisions
Recorded here because they are expensive to reverse:
CommunityMember, notPlayer. Standing is relative to the peopleyou play with.
MatchAppearanceis the rating source of truth, notTeamMember. Teams are lineupsand change; who played a given match does not. It also handles substitutes and uneven sides.
longminor units plus a currency code. Nodecimal, no floats.CommunityIdis denormalised onto every owned entity; queries filter on it explicitly,with no global query filter.
schema will not need rewriting when it arrives.
Enforced by the database, not the application
EXCLUDE USING gist, half-open ranges)Not in scope here
Left deliberately unbuilt, each wanting its own issue:
Sessionrows fromSessionTemplate(background job)NotificationOutboxAuditEventfrom aSaveChangesInterceptorLocationNote)Dashboards are not modelled: they are queries over this schema, not tables. Weather forecasts
are fetched live; only the observation taken at session time is kept.