NavAid is a static web app deployed via GitHub Pages from a workflow.
docs/— the deployed app, with browser-root files at the top level and source/data grouped below (app/,data/,i18n/,assets/,legacy/;byop/remains a stable public chart-PDF URL).mobile/— Capacitor workspace for native iOS / Android packaging. Its tinyshell/web payload openshttps://navaid.supino.orgthrough Capacitor (webDir: "shell"); native tooling stays out of the static app.the nav-waypoints projection of docs/data/cvfr-route-graph.json— 172 CVFR-layer members, of which 170 active Israeli CVFR reporting points are shipped and lazily fetched by the "Show/pin navigation waypoints" toggle. Sourced from the IAA CVFR chart waypoint reference table (page 113, 2025 edition) — see.ai/navaid-dev.mdfor refresh procedure..github/workflows/deploy.yml— Pages build + deploy..ai/— repo-tracked AI handbook: workflow, architecture, data, UI patterns, testing, and checklists..ai/navaid-dev.md— full developer guide. Read this first for any change to the app.
main— production (https://navaid.supino.org/).dev— staging (https://navaid.supino.org/staging/).- Pull requests are assembled and tested as local CI artifacts only. Unreviewed PR JavaScript is never published under the production origin.
export-leg-attributes— old draft PR branch.
Each push to main or dev re-runs the workflow, which checks out
both branches and assembles a single Pages site:
main/docs/ → root, dev/docs/ → /staging/.
- Treat
.ai/navaid-dev.mdas the source of truth for architecture, state shape, persistence keys, and deploy mechanics. - Use
.ai/README.mdas the quick index for AI-specific workflow, architecture, data, UI, testing, and checklist docs. Keep.ai/updated when behavior, storage, workflow, or test expectations change. - Cache-bust is automatic at deploy time. Do NOT bump it. Every
?v=indocs/index.htmlis the literal placeholder?v=srcand must stay that way (CI lint enforces that they all agree;tests/workflow-hardening.spec.jsenforces the placeholder itself). The deploy workflow rewrites them to the short commit SHA at upload time, along withNavAid.versionand the service-worker cache name, so the real cache-bust is per commit and automatic. Bumping a number here buys nothing and makes every pull request conflict with every other one on this single line — each merge then invalidating the rest. - Toolbar version SHA suffix is automatic at deploy time. The
same Deploy step rewrites
NavAid.versionindocs/app/core.jsfrom'1.0'to'1.0-<short-sha>', so the toolbar identifies the exact deployed commit without manually increasing the source version number. - Before creating a feature branch from
dev, update localdevand verify that it already containsmain. Fetchorigin, check outdev, fast-forward it toorigin/dev, then run the ancestry check in.ai/workflow.md. If it fails, use a reviewed feature-branch PR to bringmainintodev; do not repair a protected branch with a direct push. Before each production promotion, automation uses the opendev→mainPR's Update branch operation to bring the previous promotion merge commit back intodev; no separate sync PR is needed. Ifmaincontains production-only file changes, stop and use a reviewed maintenance PR. Never rebase shareddevor directly push protected branches as routine recovery. - Before
git commit, verify the current branch (git branch --show-current, andgit statusif needed). If it is not the branch the user intended for this work, or you are unsure, ask the user which branch to use before committing (other agents may be using a different branch). Do not commit onmain,dev, or unrelated work by mistake. - Always run
node --checkon every changed.jsfile before committing. App code is everydocs/app/*.js, plusdocs/sw.jsanddocs/i18n/**/*.js; CI enumerates these paths mechanically. - Every enhancement, bug fix, or regression must include tests. Add new
test cases to the appropriate
tests/*.spec.jsfile. If no file covers the area, create one. - Before pushing to a PR branch, check the PR is still open (
gh pr view <n> --json state). A PR merged while work is in flight is squashed from the snapshot GitHub took, so a commit pushed afterwards is silently left out: the branch and the PR body describe work that is not indev. It has happened twice. If the PR has merged, branch fresh fromdevand cherry-pick. After any merge, verify the merged code contains what the PR claimed — grepdevfor a symbol the change introduced, not the PR page. - Run only the new feature's own tests locally; let CI find regressions. CI runs the whole suite on every push, sharded across four runners, so a local full run buys a twenty-minute wait for an answer GitHub is already computing. Prove the new spec fails without the change and passes with it, push, and read the shards. Run the suite locally only when CI cannot answer the question: a change to the fixture or config every spec loads, a bisect, or an investigation where CI turnaround is the bottleneck.
- Keep
tests/README.mdin sync when adding tests that don't run in e2e-deployed, or when changing the exclusion pattern indeploy.yml. - If a push to
dev/maindoesn't triggerDeploy/CIwithin ~30 s (admin bypass can swallow the event), dispatch manually:gh workflow run Deploy --ref devorgh workflow run CI --ref dev. See.ai/navaid-dev.md"CI / Deploy gotchas" for details. - Default deploy target during development is
dev(staging). Only push tomainwhen the change is reviewed and ready for production. - Never push directly to
main. Every change must go through a feature branch and pull request targetingdev— even one-line fixes. - Every PR must be preceded by a GitHub issue. Open the issue first,
then create the PR referencing it (
Fixes #NorCloses #N). - Persist UI state to
localStorageonly via existingnavaid.*keys. The mechanically enforced registry/policy lives intests/settings-sync-allowlist.spec.js;.ai/navaid-dev.mdsummarizes the key families. Grep storage calls indocs/and update both the sync allowlist or device-local reason and the docs when adding a key. Notable keys:navaid.route— route geometry (waypoints / legs / notes).navaid.view— map center / zoom / bearing, persisted across reloads.F(no modifier) and the⌖ Fit to screentoolbar button fit the selected A3/A4/A4×2 page frame, or fit the route when no page is selected.+/=/numpad+and−/numpad−zoom the map (or loupe zoom when the magnifier is on);Mtoggles the magnifying glass. All are listed in the?cheat-sheet (SHORTCUTS_HELP_ROWSindocs/app/io.js).
- Keyboard shortcuts must be discoverable. Every global keyboard
shortcut in
docs/is listed in the?cheat-sheet modal (SHORTCUTS_HELP_ROWSindocs/app/io.js). When you add a new global shortcut, append a row to that array and add the matchingS.shortcutXxxstrings indocs/app/core.js(English defaults) +docs/i18n/he/strings.js(Hebrew). See.ai/navaid-dev.md"Keyboard shortcuts cheat-sheet" for the rendering pipeline. - No new web-app JavaScript dependencies without explicit review. The live
inventory in
docs/index.htmlis Leaflet,leaflet-rotate@0.2.8,leaflet-imageoverlay-rotated@0.2.1, andleaflet-velocity@1.7.0. Chart tiles are served fromhttps://navaid-tiles.supino.org. No build step, no bundler, no transpiler — keepdocs/plain HTML / CSS / JS. Capacitor dependencies live only undermobile/. - Tests never load a third party's server. Any change that makes the app fetch
from a new external host (a map layer, tile server, API, feed) stubs that host in
tests/_setup.jsin the same PR. The suite boots the app thousands of times per CI run, twice per push (local and against the deployed preview), so an unstubbed host gets hundreds of thousands of requests from GitHub runners. It has happened twice: flight-maps.com (its owner complained), and OpenFlightMaps (newaydata.com) after it became the default base map, fixed in #2592.tests/no-third-party-load.spec.jsfails if a booted page reaches any host outside the allowlist;NAVAID_EXTERNAL_LOG=<file>records every request that leaves the machine for an audit. Same-origin and the pinned library CDNs (unpkg, jsdelivr) are the only exceptions. Symptom to recognise: unrelated goto/reload timeouts on every PR at once, the day the third party is slow.
- App (production): https://navaid.supino.org/
- App (staging): https://navaid.supino.org/staging/
- Repo: https://github.com/msupino/NavigationApp