CLAUDE.md

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

Website of the football club AS Wëntger (www.asw.lu): a plain GitHub Pages + Jekyll site using the github-pages gem. GitHub builds and publishes it on every push to main; there is no separate deploy step. Content, YAML comments and commit-facing texts are in Luxembourgish — keep new UI text and data comments in Luxembourgish too. README.md is the editor-facing documentation (includes, menu, sponsors, Facebook/Instagram token setup).

Commands

docker compose up --build        # first time (needs internet); afterwards: docker compose up  → http://localhost:4001
bundle exec jekyll serve --port 4001   # same, with local Ruby
bundle exec jekyll build         # what the "Check links" workflow runs, followed by:
htmlproofer ./_site --disable-external --checks Links --allow-hash-href --ignore-files "/redirect/"
  • The dev container uses --incremental --force_polling; changes to _config.yml need a restart.
  • There are no tests or linters; the only CI check is the internal link check above (a broken internal link makes the commit ✗).
  • Data fetchers (Python 3.12, run by scheduled GitHub Actions which commit their output): python tools/fetch_matches.py, fetch_rankings.py, fetch_facebook.py (needs FB_PAGE_TOKEN), fetch_instagram.py, fetch_shop.py.

Architecture

  • Pages: pages/** get layout: page and permalink: /:basename/ via _config.yml defaults, so the URL is the file name only — sub-folders just mirror the menu, and basenames must be unique across pages/. Renames need redirect_from: in the front matter plus an update of _data/menu.yml (the menu is data-driven, up to 3 levels, rendered by _includes/nav.html).
  • Root-relative URLs everywhere: write /kalenner/, /images/.... _layouts/default.html post-processes the rendered HTML and prefixes site.baseurl onto every ="/…" and url("/… so the site also works under a GitHub project path.
  • Data-driven content (_data/*.yml) rendered by includes; most pages are thin shells calling an include:
    • ekippen.yml (teams: FLF/FuPa ids, calendar category) → ekipp.html, ekippen-carousel.html, ranking.html, spielplan.html.
    • persons.yml is the single source for all people; each person has roles with group = comite, supporterclub, asw-reporter, a commission id (kommissiounen.yml) or a team id (ekippen.yml). person-list.html collects and sorts them (sortOrder → roleName → name); person-card.html derives the photo path from the name: "SCHOLZEN Guy" → /images/persons/scholzen_guy.{jpg,jpeg,png,webp} (slugified, no accents; UPPERCASE words = surname), initials if missing. Photos are 4:5.
    • sponsors.yml, deals.yml, terrainen.yml, sportzeitung.yml, aswreporter.yml — schema documented in each file’s header comment.
  • Generated data — do not edit by hand (overwritten by workflows): _data/calendar_matches/ (hourly, from api.asw.lu; the fetcher deliberately strips volunteer/referee personal data), _data/rankings/ (hourly, FLF or FuPa), _data/facebook_posts.json + assets/fb/, _data/instagram_stories.json + assets/ig/, _data/shop.json + images/shop/. Because bots push often, git pull --rebase before pushing.
  • Styling: Sass partials in _sass/ (_nav, _layout, _components, _cms, _base, _fonts) compiled via assets/css/main.scss; club colours come from colors: in _config.yml. Fonts are self-hosted in assets/fonts/. Client JS: assets/js/site.js (menu etc.) and assets/js/match-calendar.js.
  • Images are stored as WebP. _site/ is build output (git-ignored); never edit it.
  • Never commit raw WordPress exports (*.WordPress.*.xml) — they contain personal data.