Skip to content

Running the platform

The website

Every install comes with a public website under its own brand, at the backend's address: the home page at /, and the legal pages and account deletion at /legal/... and /account/delete. Pages render on the server with Twig, so they work without JavaScript and search engines read them whole; Turbo and Stimulus only make them faster. The look: the brand's gradient across the header and the hero, a soft page with white cards, and Mulish. Sports is dark blue until a brand picks its own colours.

The brand

Settings, Website in the admin sets the look; a change shows on the next page load, with no rebuild:

  • Brand colour: buttons, links and highlights (dark blue when left empty). Any hex colour works: text on it turns white or dark to stay readable (WCAG AA, 4.5:1), and the colour as text on white is darkened just enough to read.
  • Header and hero gradient: one or two colours. Left empty, it runs through shades of the brand colour, darker to lighter, each kept readable under the header's text: a blue brand gets blues.
  • Footer and page background colours: a deep navy and a soft blue-grey when left empty.
  • Font: Mulish, DM Sans, Inter or the device's own.
  • Tagline under the name on the home page, and a home page image behind the gradient.
  • The app's store links: "Get the app" shows in the header, the hero and the footer once one is set.

The name and logo are the platform's own (Settings, General). One build serves any brand: the layout sets the brand as CSS custom properties (--brand-primary, --brand-on-primary, --brand-primary-text, --brand-gradient, --brand-on-header, --brand-footer, --brand-on-footer, --brand-page and --brand-font), and every colour in the styles follows from them.

The home page

Under the hero (the name, the tagline and the numbers: competitions running, teams and matches this week), the home page shows these sections, in this order:

SectionWhat it shows
FixturesToday's matches, played ones with their score; when nothing is on today, the next ones
ResultsThe latest confirmed results
TableThe table of the league with the latest result, top eight
CompetitionsThe competitions running and taking entries
How to joinThe competitions taking entries, with the app's links
VenuesThe venues, with their pitches and courts and sports

The organisation type (Settings, General: a league, a venue or a club) decides which show: a league shows everything but the venues, a venue everything but the table, and a club all of them. Settings, Website can turn each one on or off instead. A section with nothing to show stays out. A confirmed result is on the home page at once, and the page is never more than a minute old. Sponsors come with the website editor.

Competition pages

/competitions lists every public competition: those running, those taking entries, and the archive, by season, of the finished ones. Each competition has a page at /competitions/<its address>, and each of its divisions after the first at /competitions/<its address>/<division>, with tabs between them. A page shows the division's stages, each in its own format:

FormatShown as
League (round robin)The table, with promotion and relegation marked
GroupsA table per group, with who goes through marked
KnockoutThe draw, round by round, with byes, scores and the champion
Box leagueThe boxes of the latest round, with who moves up and down, and the round's dates
LadderThe ladder in its order

Then the fixtures still to play and the results, by round where the stage plays in rounds and by day otherwise. Tables come from the same standings the admin shows; a closed season's are the final tables it kept. "Other competitions" switches to another one. Drafts are never shown.

Entering a team

/enter lists the team competitions taking entries, with the places left in each division. Entering takes three steps on /enter/<competition>:

  1. The details: the division, the team's name, the captain's name and email, and the terms.
  2. A code emailed to the captain proves the address. Then the team is made with the captain in its squad, and entered by the competition's rules: in while there's room, on the waiting list once a division is full (a full competition offers only that), or holding its place until its entry fee is paid.
  3. Paying, where there's an entry fee: the captain goes to the payment provider's checkout, and the entry is accepted only once the payment succeeds. Without online payment, the captain pays the organiser.

The captain then gets the squad's invite link (on the page and by email) and the app's links. A new captain's account has no password yet: they choose one in the app with "Forgot password?". The team and its entry are in the admin like any other.

Teams, players and venues

  • A team's page (/teams/<id>) has its form (the last five results), its fixtures and results, and the competitions it plays in. Its squad shows only when the team allows it: its captain chooses in the app, or the admin on the team's page (Squad on the website).
  • A player's page (/players/<id>) exists only when the player chooses it in the app. Then it has their levels, their teams and their matches. Otherwise there's no page at all, their name is never a link, and they aren't in the sitemap. The admin can see the choice but never makes it for them.
  • A venue's page (/venues/<address>) has its address, a map and directions, its pitches and courts, its opening hours, and the competitions run or played there.

Team and player names on the competition and home pages link to their pages where they have one.

The sitemap

/sitemap.xml lists every public page: the home page, the competitions and their divisions, the teams in public competitions, the players who chose a public page, the venues and the legal pages. /robots.txt points search engines to it.

Website, Menus in the admin edits the header and footer menus: each link has its text, its address (a page on the site starting with /, another site's https:// address, or a mailto:), its position and, optionally, the one language it shows in. The header shows the home page until it has links of its own. The terms, the privacy policy and account deletion are always in the footer.

Languages

A page's address says its language: ?lang=ro for Romanian, and the site's default language (Settings, General) without it. The header and the footer link every page to its other languages.

Caching

A page is rendered once and kept until something it may show changes: a fixture, a result, a competition, a team or player, a venue, a legal page, a menu or the brand. Pages are public and carry nothing personal, and a visitor who has the page already is told it hasn't changed. Whatever happens, a page is at most a minute old.

Themes

For what the settings can't change, an install can have a theme:

themes/
  acme/
    templates/      overrides, at the same paths as templates/
      web/_footer.html.twig
    assets/
      theme.css     extra styles, loaded after the website's
    theme.yaml      written by app:theme:check --record

Set THEME=acme in the environment, and build the assets with it: THEME=acme npm run build, or, with Docker, THEME=acme docker compose up -d --build. Templates in themes/acme/templates are used instead of the platform's ones at the same path. These can be overridden and kept across updates:

TemplateWhat it is
web/layout.html.twigThe frame of every page
web/_header.html.twigThe header and its menu
web/_footer.html.twigThe footer
web/home.html.twigThe home page
email/layout.html.twigThe frame of every email

Others can be overridden too, but they change more often and aren't supported across updates. Start an override by copying the platform's template, and keep its blocks and the variables it uses (web holds the brand, languages and menus). A theme's styles can use the website's utilities and brand colours, like gradient-band, card, btn-primary, bg-primary, text-on-primary and text-primary-text.

After updating the platform, run php bin/console app:theme:check. It lists each override as ok, drifted (the platform's template changed since the override was reviewed: compare them and bring over what's new), not_recorded, unsupported or base_removed, and fails while any isn't ok, so it can run in a deploy. Once reviewed, php bin/console app:theme:check --record marks them as reviewed.

Found a mistake? Tell us.