Config Hierarchy
Most settings in Staty live in a config object that is shared across the entity tree. When Staty needs a setting’s value for a given division, it resolves it by walking from the most specific level to the least specific and taking the first level that has a value set.
Precedence
division > league > tournamentThe most-specific level with a value wins. If a division doesn’t set a field, the league’s value applies; if the league doesn’t either, the tournament’s does. A field left unset everywhere falls back to its platform default — one canonical set of defaults applies everywhere (for example: stats are shown, schedules are visible, rosters are unlimited, a coach is required, and the waitlist promotion payment window is 48 hours).
The registration is not a level in this hierarchy. Settings made while creating or editing a registration (roster requirements, fees, donations) are stored on its parent tournament or league/contest, which is where they resolve from.
Unset is not the same as off. A level that leaves a setting alone inherits it; a level that explicitly sets it — including to off, or to a capacity of 0 — is making a real override that its parent can no longer change. That’s what lets a division re-enable something its tournament turned off. Staty only stores a value at a level when you actually change it there, so opening a division’s Settings and saving doesn’t quietly pin every toggle on that division.
This lets you set a sensible default high up (e.g. on the tournament) and override it only where it differs (e.g. one division with a different capacity).
A value only “wins” if it is actually set. Setting a field on a division overrides the same field inherited from its league or tournament.
Common config fields
| Field | Purpose |
|---|---|
capacity | Max teams in a division (0 = unlimited). |
hasWaitlist | Allow paid overflow registrations beyond capacity. |
autoPromote | Automatically seat the next paid waitlisted team when a spot opens. |
minPlayers / maxPlayers | Roster size bounds (see Roster size bounds below). |
showStats | Whether stats are visible to the public (see Hiding stats — it never hides scores, schedules or standings). |
statDisplayMode | Public aggregate stats as per-game average or season total. |
gameStats | The stat columns tracked, keyed by sport. |
hideStandings | Hide the public division Standings tab (independent of hideSchedules). |
breakPlayoffTiesBySeed | Award a tied playoff game to the higher-seeded team (highlighted publicly, and advanced in the bracket). |
paymentProduct | The registration fee for teams under this level — a division or contest can override its tournament’s fee. |
donationProduct | The optional donation offered at checkout, same precedence as the fee. |
How the public site resolves these
The public site does not resolve the hierarchy itself. The API resolves the levels
server-side and returns the answer on each division as effectiveConfig, which is what the
public pages read — the browser never holds every parent document, so it could not resolve
the chain reliably on its own.
Roster size bounds
minPlayers / maxPlayers follow the same precedence as every other field, and the same resolved numbers are used everywhere — the roster form a team fills in, the embedded registration form, and the server-side check that runs when the roster is saved. What a team is shown is exactly what is enforced.
- A contest or division max overrides the tournament’s. A tournament set to 5 with a contest set to 8 allows 8-player teams in that contest. (The numbers entered in the registration wizard are stored on the parent tournament or contest.)
0or unset at a level means “inherit from the level above”, not “no players allowed”.- Unset at every level means there is no maximum, and a minimum of 1.
- Lowering a max later never strands a team that is already above it: an existing over-limit roster can still be saved and shrunk — only growing it further is blocked.
Hiding tabs (Hide Teams / Hide Schedules / Hide Standings)
These follow the same precedence as everything else, so a contest or division can turn a parent’s setting back off. Turning Hide Schedules on for a tournament hides it for every contest and division beneath it that hasn’t set its own value; switching it off on one division re-exposes that division only.
In the admin Structure → ⋯ → Settings drawer, a toggle showing a value it inherited is labelled “Inherited from …”. Flipping it there records an override for that entity.
Note this hides the public tab and its content — it never removes the tournament, contest or division from your site’s navigation. Hide Schedules also removes that entity’s games from the homepage sidebar (Live Results, Upcoming Games, Latest Results), so hidden schedules don’t leak onto the front page.
Registration-only exceptions
A few fields are not resolved through the hierarchy — they are read directly from the registration and should only be set there:
isTestMode— the registration’s Test Mode switch.gateByStartDate— publish a registration page publicly while keeping sign-ups locked untilstartDate(see Manage Registrations).gateByEndDate— close new sign-ups afterregistration.endDatewhile keeping the page (and existing teams) fully visible and editable (see Registration End-Date Gate).showAllRegistrationTeams— show the public “Teams by Division” roster on the registration details page.
Both date gates are interpreted and displayed in the registration’s single timeZone (an IANA name like America/Los_Angeles) — the comparison itself uses absolute instants, so it’s timezone-correct everywhere.