Skip to content

gc-tour-planner

Plan geocaching tours: pick a starting point and radius, filter caches by type / attributes / landuse (forest vs. city), find a dense cluster, and get a closed walking loop with a parking spot.

Live site: https://gctp.brookman.live — currently covering the Netherlands and North Rhine-Westphalia (NRW), Germany (the regions whose OSM map + walking-route data we host). Want another area? Open a region request — we add regions based on demand.

Status: actively developed and runnable end-to-end. Milestones M1–M5 and most of M6 are shipped — GPX ingest, map + filters, OSM context, routing infrastructure, and tour planning (cluster discovery → optimised loop → parking), plus user accounts (email + Google sign-in), server-saved tours, and a public landing page — all backed by a NestJS API, a React/MapLibre web app, and async precompute workers. The remaining M6 piece is read-only share links (M6-δ). See the full breakdown in docs/requirements/roadmap.md.

What it does

  • Define a search area by center + radius — use the browser's "use my location", or pan the map.
  • Hard filter caches by type (Traditional, Multi, …) and attributes (e.g. dog-allowed, needs special tool).
  • Soft preferences scored against OpenStreetMap landuse polygons (prefer forest/park, avoid residential), backed by three seeded profiles — forest-heavy, urban, balanced.
  • Detect clusters of caches that admit a closed walking loop within a distance / time budget, and pick from the top candidates.
  • Build the loop with a pure-TypeScript greedy planner (DBSCAN clustering → Nearest-Neighbor + 2-opt), with a score breakdown panel.
  • Choose a parking / start point — from parking waypoints embedded in the Groundspeak GPX, nearby OSM parking facilities, or the nearest OSRM-routable road.
  • Upload a GPX and watch routing + landuse precompute run in the background, with an operator panel and a queue dashboard.

Coming next

  • M6-δ — read-only share links (accounts + server-saved tours have already shipped).
  • M7 — OKAPI source adapter (Opencaching networks).
  • M8 — GC.com adapter, gated on partner-API approval and kept feature-flagged off.

How it works

  • Data ingest: GPX uploads today (Groundspeak Pocket Queries + generic). Per-user GPX isolation — uploaded caches are visible only to their owner. OKAPI (M7) and GC.com (M8) source adapters are designed in but not yet shipped.
  • Spatial backend: Postgres + PostGIS holds caches, additional waypoints, OSM landuse polygons, OSM parking facilities, memoized routing legs, and per-cache precompute freshness state.
  • OSM context: landuse polygons + parking facilities are imported into Postgres by a one-shot osm2pgsql pass over an OSM extract (single Lua, two tables) — no Overpass sidecar.
  • Routing: self-hosted OSRM (foot profile) preprocesses the OSM extract on first boot. GPX upload completion enqueues background walking-precompute (OSRM leg matrices for new caches' neighbours) and landuse-refresh jobs via BullMQ + Valkey, surfaced in an admin panel and a bull-board queue dashboard.
  • Tour planner: a pluggable TourPlannerStrategy. The shipped strategy is a pure-TypeScript greedy planner — DBSCAN to find candidate clusters, then Nearest-Neighbor + 2-opt for the loop. A solver-based strategy (Timefold / OR-Tools) plugs in later behind the same interface.

Run it

Prereqs: Node + pnpm, and Docker (for Postgres/Valkey/OSRM).

pnpm install        # bootstrap the monorepo

pnpm dev            # dev stack: postgres + valkey + shared OSRM, runs migrations,
                    # then api + web with hot reload and interleaved logs
pnpm dev:down       # stop dev infra (volumes preserved)

For a full production-shape stack (everything in containers, OSRM preprocessing + OSM import on first boot):

cd infra && cp .env.example .env && docker compose up --build

Common tasks: pnpm lint · pnpm typecheck · pnpm test · pnpm test:e2e · pnpm licenses:check. More detail — including the dev/UAT split — is in CLAUDE.md and docs/sdlc/.

Repository

This is a pnpm + Turborepo monorepo:

apps/api    — NestJS service (caches, gpx, osm, routing, tours, landuse-profiles, jobs, admin, …)
apps/web    — React + Vite frontend (MapLibre GL JS): search, map, planning, upload, admin
packages/   — shared zod types, db migrations + Kysely schema, lint/tsconfig presets
infra/      — docker-compose, OSRM bootstrap, osm2pgsql import, Dockerfiles
docs/       — requirements/, architecture/, design/, sdlc/, adr/, LICENSING, PLANNER_TUNING

Full layout and module-by-module breakdown: docs/architecture/repo-layout.md.

Documentation

Document What it covers
docs/requirements/ Functional + non-functional requirements
docs/architecture/ System architecture, repo layout, modules
docs/design/ Data model, algorithms, API surface
docs/sdlc/ Branching, testing, migrations, deploy, docs
docs/PLANNER_TUNING.md Every PLANNER_* env knob + symptom→knob guide
docs/LICENSING.md GPLv3 compliance, third-party data terms
docs/adr/ Architecture Decision Records

Tech stack (locked)

TypeScript end-to-end. NestJS · React + Vite · MapLibre GL JS · Postgres 16 + PostGIS 3.4 · Kysely + node-pg-migrate · zod · BullMQ + Valkey (not Redis, see ADR-0004) · self-hosted OSRM · Docker Compose · GitHub Actions.

License

GPL-3.0-or-later — see docs/LICENSING.md for third-party data attribution (OpenStreetMap ODbL, osm2pgsql, OSRM, MapLibre).

Geocache data sourced from Groundspeak (geocaching.com) is not redistributed by this project; users upload their own GPX files.

Contributing

See CONTRIBUTING.md and CODE_OF_CONDUCT.md. The roadmap is split into milestones M1–M8 in docs/requirements/roadmap.md.

About

Plan geocache tours: clustered closed loops with soft-constraint scoring over OSM landuse, parking-aware, OSRM walking distances. Multi-user, Docker-portable.

Resources

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages