Skip to content

Campgrounds & Campsites: a first-class, multi-agency pillar (data, availability, Camp Watch, trip + ranger + viz)#27

Merged
johnymontana merged 5 commits into
mainfrom
campgrounds
Jun 28, 2026
Merged

Campgrounds & Campsites: a first-class, multi-agency pillar (data, availability, Camp Watch, trip + ranger + viz)#27
johnymontana merged 5 commits into
mainfrom
campgrounds

Conversation

@johnymontana

Copy link
Copy Markdown
Owner

Turns campgrounds from a campground-level detail hiding inside park pages into a first-class
TrailGraph pillar — site-level data, live availability + cancellation alerting, multi-agency
coverage, and deep Map / Plan / ranger / data-viz integration — built entirely on open,
attributable data (RIDB · USFS · OSM/Overpass). Extends the existing :Campground spine; the
already-parsed ridbId is the federation key, so the federal import unifies with NPS campgrounds
in place
instead of duplicating.

82 files, +5,501 / −17. 956 unit tests · 18 campground integration tests · 8 campgrounds +
15 hydration e2e · eve info 0 errors · clean pnpm build. Each phase was driven live in the
browser before merge (live testing caught two real bugs — see below).

Phase 1 — Federal data foundation + Campgrounds tab

  • Graph model: :Campsite (HAS_SITE), :Agency (MANAGED_BY), :RecArea (IN_RECAREA),
    (:Campground)-[:NEAR {miles}]->(:Park) + NEAR_TRAILHEAD:Trail (migrations 026/027).
  • RIDB ingest (lib/datasources/ridb.ts + sync-campgrounds-ridb/sync-campsites-ridb): unifies
    NPS↔RIDB by ridbId (no duplicates, source='nps+ridb'), checkpointed/resumable, ~100k sites.
  • lib/campgrounds.ts query layer (searchCampgrounds/campgroundDetail/campgroundFacets),
    /campgrounds faceted finder + CampgroundCard + /campgrounds/[id] site-level detail, nav + search.

Phase 2 — Availability + Camp Watch (built, gated OFF)

  • lib/datasources/campAvailability.ts (the rec.gov endpoint is unofficial → hard-gated by
    CAMP_AVAILABILITY_ENABLED, ships OFF; every surface degrades to a recreation.gov deep link, with
    backoff + a clear UA). On-demand /api/campgrounds/availability (rate-limited) + finder chips.
  • Camp Watch cancellation alerting: :CampWatch model + /api/camp-watch poller cron
    (*/15, snapshot-diff + 30-min throttle) + Resend alert email, reusing the existing
    watch/digest/email substrate. Gated derive-booking-difficulty.

Phase 3 — Plan + ranger + memory

  • (:Stop)-[:STAYS_AT]->(:Campground) nested trip lodging (TripBuilder "Sleeping here", GPX waypoint,
    offline field sheet, pure suggestLodging).
  • Camp memory bridges (:CampPrefs + amenity REQUIRES + SAVED:Campground) injected into the
    ranger's per-turn memory block.
  • 9 ranger tools (find_campgrounds, check_campsite_availability, set/list/clear_camp_watch,
    add_campground_to_trip, campground_booking_window, set_camp_preferences, save_campground)
    • 4 chat cards. The ranger never books or pays — it surfaces deep links and (with permission)
      sets a watch.
  • Comparison scorecard viz (radar + table, /campgrounds/compare?ids=…).

Phase 4 — Reach (open-data scope)

  • Real OSM ingest (osm-camp.ts Overpass camp_site/caravan_site/camp_pitch, ODbL) for
    state/private/dispersed coverage.
  • Real cross-source entity resolution (resolve-campgrounds): dedups OSM vs the federal canon by
    name-Jaccard + <250 m geodistance, merges sourceIds and raises dataConfidence.
  • Map camp-lens ("Color campgrounds by" free/dispersed/hookups/ADA/first-come).

Honest caveats / scope

  • Availability is OFF by default (unofficial endpoint) — re-validate against recreation.gov's
    "Use Our Data" terms before enabling in prod. No code path hard-depends on live data.
  • All new ingest/derive is gated (SYNC_CAMPGROUNDS, ENRICH_OSM_CAMP, RESOLVE_CAMPGROUNDS,
    DERIVE_BOOKING_DIFFICULTY) and needs RIDB_API_KEY (free).
  • Deferred (partner-gated, not open data): USFS-GIS ArcGIS ingest, state-park reservation systems
    (ReserveAmerica/UseDirect/Aspira), private/affiliate (Hipcamp/The Dyrt), community reviews,
    Camp-Watch monetization tiers, and the availability-calendar/occupancy/constellation charts (data-gated).

Bugs caught by live browser testing

  • USFS campground card showed "NPS" (provenance label fell through to the default).
  • The weather emoji rendered inside a Chakra <Icon> 500'd the detail page.

Verification

pnpm typecheck · pnpm test:unit (956) · RUN_INTEGRATION=1 pnpm test:integration (campgrounds +
camp-watches) · pnpm test:e2e (campgrounds + compare; no regressions in plan/hydration) ·
pnpm exec eve info · pnpm build. Setup: add RIDB_API_KEY, run pnpm db:migrate (026/027), then
pnpm campgrounds:sync (or SYNC_CAMPGROUNDS=1).

@vercel

vercel Bot commented Jun 27, 2026

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
trail-graph Ready Ready Preview, Comment Jun 28, 2026 5:38pm

Request Review

@johnymontana
johnymontana merged commit 3370bfc into main Jun 28, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant