Files
TREK/wiki/Contributing.md
Maurice b401da2264 fix(maps): default the Leaflet basemap to OpenFreeMap
CARTO started stamping "API KEY REQUIRED" across every keyless basemap tile
on 26.08.2026. #2060 added a key field as the immediate answer, but it leaves
a self-hosted instance needing an email exchange with CARTO before its maps
look right, and every default in the client still pointed at CARTO. Default
to OpenFreeMap Positron instead: no key, no account, no request limit,
commercial use allowed, attribution required.

OpenFreeMap serves vector tiles only, so the Leaflet basemap is a MapLibre
style document rather than an XYZ template. maplibre-gl-leaflet hangs a GL
canvas into Leaflet's own tile pane, which leaves everything above it alone -
markers, GeoJSON, clusters, plugin layers, the custom panes, and the click
handling, since Leaflet's CSS already puts pointer-events:none on that layer.
maplibre-gl still arrives only through a dynamic import, so no chunk that
draws a map grows by a megabyte.

Switched: the trip planner, the MapView fallback every preview goes through,
the journey map, collections, the atlas, the shared trip page and the offline
tile prefetch. OpenFreeMap Positron and Bright join the tile presets in
settings, the admin defaults and both mobile screens.

A CARTO template that is already saved keeps working when a key backs it -
that stays a supported choice. Without a key it is not drawn at all:
resolveTileUrl falls back to the default rather than to a watermark, so an
instance that upgrades with one in its settings sees the new basemap
immediately and needs no migration. The stored value is left as it is, so the
Map settings tab still shows what was chosen and the warning underneath it
explains why - one sentence appended, in all 23 locales.

OpenFreeMap asks for a credit of its own; OpenStreetMap alone under its tiles
is wrong and a licence problem. attributionForTile() derives it from the URL
rather than from a flag at each call site, and the shared trip map, which
carried no attribution at all, now gets one.

Offline maps keep working and get cheaper. A vector style is four things
instead of one, so sync/glPrefetcher.ts walks the style document, its sprite,
the Latin glyph ranges of each font stack it uses, the TileJSON - the planet
path is versioned, so guessing it answers 200 with an empty body - and then
the .pbf tiles. Over the Berlin bounding box TREK computes, raster z10-16 is
2237 requests and 34.6 MB and gives up above z16; vector z10-14 is 177
requests and 32.1 MB and stays sharp above that, because MapLibre scales the
z14 tile rather than asking for another. The Workbox rule for
tiles.openfreemap.org moves to CacheFirst and shares the prefetcher's cache,
so browsing tops a downloaded region up instead of filling a second copy
beside it - a versioned tile path can never be stale. Clearing offline maps
clears it too.

The atlas loses its second raster layer. It existed to warm the HTTP cache of
neighbouring zoom levels, which a vector basemap does not need; a second one
would only cost a second WebGL context. OpenFreeMap has no label-free style,
so its labels are switched off on the live map instead - they are all symbol
layers, while borders and coastlines are line and fill - re-armed on
style.load so a theme switch keeps them off.

Theme changes call setStyle in place rather than rebuilding the layer: a swap
per toggle would leak a WebGL context, and browsers cap those in the low
teens.
2026-08-29 00:51:43 +02:00

3.4 KiB

Contributing

Thanks for your interest in contributing to TREK! Here are the guidelines for submitting pull requests.

Before You Start

  • Ask in Discord first — Before writing any code, pitch your idea in the #github-pr channel on our Discord server. We'll let you know if the PR is wanted and give direction. PRs without prior approval will be closed
  • Check existing issues — Look for open issues or discussions before starting work
  • Target the dev branch — All PRs must be opened against dev, not main. Exception: PRs that only modify files under wiki/ may target any branch
  • One thing per PR — Keep PRs focused on a single change. Don't bundle unrelated fixes

Pull Request Guidelines

Code Quality

  • Write clean, readable code that matches the existing style
  • No unnecessary abstractions or over-engineering
  • Don't add features beyond what was discussed in the issue
  • Don't add comments unless the logic isn't self-evident
  • Don't add error handling for scenarios that can't happen

What We Look For

  • Does it solve the stated problem? — The PR should match the issue it addresses
  • Is it minimal? — No extra refactoring, no "while I'm here" changes
  • Does it break anything? — Breaking changes are not acceptable
  • Is the code clean? — Consistent style, no debug logs, no dead code

Commit Messages

Use conventional commits:

fix(component): short description of what was fixed
feat(component): short description of new feature

PR Description

Follow the template provided by default (.github/PULL_REQUEST_TEMPLATE.md).

What Will Get Your PR Closed

  • PRs that weren't discussed and approved in #github-pr on Discord first
  • PRs that add unnecessary complexity (e.g. a redo button when undo already exists)
  • PRs with breaking changes
  • PRs that change code style or formatting across unrelated files
  • PRs that add dependencies without justification

Development Setup

See the Development Environment page for the full setup guide, including forking, remote configuration, branch conventions, and available scripts.

Tech Stack

Layer Technology
Frontend React 19, TypeScript, Zustand 5, Leaflet, Tailwind CSS 3.4, Vite 8 (Rolldown)
Backend NestJS 11 (Express 4 adapter), TypeScript, better-sqlite3, Zod (@trek/shared)
Real-time WebSocket (ws)
Database SQLite with WAL mode
Auth JWT (HS256), bcrypt, TOTP MFA, OIDC
Maps Leaflet + react-leaflet (default, OpenFreeMap vector basemap via maplibre-gl-leaflet), MapLibre GL, Mapbox GL, OSRM, Nominatim
i18n 23 languages, EN canonical (locale directories live in shared/src/i18n/)

Every translation key must exist in all 23 locales — the i18n Key Parity CI job fails on drift, so run npm run i18n:parity:strict --workspace=shared before pushing. Two directory names differ from the language they hold: Brazilian Portuguese is br, Greek is gr.