Duplicates the team's Google Sheets matchup-matrix template once per
opposing team at a loaded event, pre-filled with names, factions,
career win% (all already computed by this page), and cleaned army
lists. New "Which team is yours?" selector + Generate Matrix button,
team-events only.
- Auth: Google Identity Services token client (drive.file +
spreadsheets scopes) — the viewer signs in with their own Google
account via a real OAuth popup, no backend, no client secret.
- Template layout is located at runtime by searching each tab for its
own placeholder text ("Player N - Faction", "Opponent N") rather
than hardcoded A1 ranges, so it survives the template changing later.
Distinguishes the real input area from the template's own "mobile
matrix" mirror and reference sections (which repeat the same
placeholder text) by checking for literal typed values vs formulas —
CSV export can't tell these apart, only the real Sheets API response
can, which is how this was actually verified before writing this.
Auto-picks between the template's 5-man/8-man tab variants by team
size.
- List cleaning via a vendored copy of desjani's 40k-compactor
(src/vendor/40k-compactor/, see NOTICE.md) — it isn't actually
published to npm despite documenting `npm install 40k-compactor`
(verified: 404 against the registry under every plausible name), so
it can't be a normal dependency; vendored instead, MIT per direct
confirmation from the maintainer. Verified against 40k-compactor's
own sample list fixtures with real Node before committing.
- Generating a matrix needs the same BCP auth token already used for
faction/disposition backfill (list text is a subscriber-gated
endpoint) — reuses the existing token UI/storage as-is; missing
lists are reported, not a hard failure.
- nginx CSP updated (script/connect/frame-src) for Google's identity
script and the Drive/Sheets REST APIs.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SBzcNkW7JcYipnAX6HfgmK
The committed .conf files were stale pre-certbot templates that no
longer matched what's actually running on gg1-roc-web1 (certbot --nginx
had rewritten 40k-rankings/aos-rankings/kingmaker's structure, and in
the process 40k-rankings and aos-rankings lost their security headers
entirely). Replaced each with the true live config, plus the new
location /images/ and location = /footer.html alias blocks that were
applied directly on the server.
Also fixed on gg1-roc-web1 while there (not reflected in this repo,
just noting for the record):
- kingmaker's TLS cert had expired 2026-08-26; renewed.
- certbot-renew.timer was enabled but never started (box hasn't
rebooted in 172 days), so nothing was auto-renewing; started it and
ran a full certbot renew, which also caught 40k-rankings/aos-rankings
sitting inside their renewal window.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SBzcNkW7JcYipnAX6HfgmK
Merge the four independent gateway-gamers.net site repos (40k-rankings,
aos-rankings, kingmaker, scouting) into one monorepo under sites/,
preserving each site's full commit history via a manual subtree-style
merge (git-subtree isn't available in this environment).
- shared/: header.template.html (nav swapped in per site), footer.html,
and images/ — previously byte-identical copies duplicated 4x (~100MB).
- Each site's public/footer.html and public/images are now symlinks into
shared/; public/header.html is generated at predev/prebuild time from
shared/header.template.html + the site's own nav.html, so nav bars stay
individual while everything else about the header is shared.
- Single root .gitlab-ci.yml with path-scoped build/deploy jobs per site
plus a deploy:shared job, replacing the 4 separate per-repo pipelines.
- nginx confs (kept per-site as reference, same as before) gain
location /images/ and location = /footer.html alias blocks pointing at
a shared webserver directory, so the deployed site no longer duplicates
the images either — see README.md for the full layout and the runbook
for applying this on the webserver.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SBzcNkW7JcYipnAX6HfgmK