Adventure Planner — Multi-Sport Trail Exploration
2025-11-01
A PNW-focused planner that fuses trail search, live wildfire + air quality, and lake/river swim safety to generate time-smart, activity-aware adventures.
Highlights
- Trail discovery with drive-time + difficulty filters
- Map exploration with rich detail panels
- Wildfire + AQI overlays and proximity signals
- Water safety metrics + swimability at a glance
- NPS data integration for official trail info
Technical Deep Dive
The API Learning Curve
This was my first time working with both the National Park Service API and OpenRouteService. The NPS API had surprisingly generous rate limits but required careful data transformation—their schema is optimized for parks, not trails, so I had to infer trail attributes from park activities and descriptions. OpenRouteService was more straightforward for geocoding but had stricter rate limits, which forced me to implement smart caching and fallback estimations.
Key Architectural Decisions
Edge Functions vs. Client-Side API Calls
I built a Bolt Database edge function for the NPS data sync rather than calling directly from the client. This lets me use the service role key securely and batch-process trails without exposing credentials. The tradeoff: edge functions add deployment complexity and debugging is harder than client-side code. But it was worth it for security and the ability to transform data server-side.
Database Schema: Unique Constraints Matter
Initially, my trails table didn't have a unique constraint on the name column, which caused my upsert logic to fail silently. Adding UNIQUE(name) made the sync idempotent—I can re-run it without creating duplicates. This was a lesson in thinking through data integrity upfront rather than patching later.
Map Library: Why Leaflet Over Alternatives
I chose Leaflet because it's lightweight, has great documentation, and doesn't require API keys for basic OpenStreetMap tiles. Google Maps would have been overkill (and expensive), and Mapbox felt like premature optimization. Leaflet gave me the right balance of features and simplicity for a time-boxed workshop project.
Handling Rate Limits & Errors
OpenRouteService's free tier allows 2,000 requests/day. For driving time calculations, I implemented a fallback that estimates times using straight-line distance × average speed when the API fails or hits rate limits. This graceful degradation means the app stays functional even when the routing service is unavailable. Users get "estimated" times instead of precise routes, but the experience doesn't break.
What I'd Do Differently
- Pre-seed the database: Instead of requiring users to click "Sync NPS Trails," I'd pre-populate the database with curated trail data during deployment. The sync button is useful for updates but adds friction to first-time users.
- Better error messaging: When API calls fail, I show generic error toasts. I should surface more specific guidance: "Rate limit reached—try again in an hour" or "Check your internet connection."
- Performance optimization: Loading all trails and then filtering client-side works fine for ~100 trails, but won't scale to thousands. I'd implement server-side filtering and pagination if expanding beyond the Pacific Northwest.
- Test with real users: I assumed people would understand the filters and map interactions, but I should validate that with actual outdoor enthusiasts who aren't developers.
What Worked Really Well
- The time constraint: Building under pressure forced me to ship something functional rather than perfect. I cut features aggressively (multi-day trip planning became a placeholder) and focused on the core value: finding nearby trails with safety info.
- Starting with free APIs: Not having a budget meant I had to be creative and learn tools I wouldn't have considered otherwise. Paid APIs would have been easier, but I learned more by working within constraints.
- Real data from the start: Integrating the NPS API early meant I was testing with realistic trail names, locations, and attributes rather than placeholder data. This surfaced edge cases (parks without trails, trails without coordinates) that I had to handle properly.
Next Steps & Future Ideas
This was built in an evening, but there's a clear path forward if I wanted to turn it into something people actually use regularly:
Permit Discovery & Booking
Many popular trails (Enchantments, Mt. Rainier zones, Whitney Portal) require permits that book up months in advance. I'd love to integrate Recreation.gov's API to show permit requirements, availability, and direct links to book. Even better: set up alerts when permits become available for specific trails or date ranges. This would solve a real pain point—finding out you need a permit only after you've planned your whole trip.
Turn-by-Turn Routing
Right now, the app shows driving time to trailheads but doesn't provide actual routes. Adding turn-by-turn directions using OpenRouteService's routing API would make the planning experience complete—from "I want to hike" to "here's exactly how to get there." The challenge: balancing API call costs with user value, especially for users who just want to browse without committing to a specific trail.
Strava Integration
Connect to Strava's API to pull in completed activities and suggest similar trails based on your history. If you've run 10Ks on moderate trails with elevation gain, the app could surface comparable routes in new areas. This would also enable social features—see which trails your Strava connections have completed, read their reviews, or plan group adventures. The data is already there; it just needs to be surfaced usefully.
Other Ideas Worth Exploring
- Weather forecasting: Integrate weather APIs to show trail conditions, snow levels, and optimal visiting windows. "Don't attempt this trail before July" is information I wish I'd had on several trips.
- User-generated content: Let people upload trip reports, photos, and recent condition updates. Official APIs are great but often lag behind real-time conditions.
- Multi-day trip planning: The placeholder "Plan" mode could become a full itinerary builder—string together multiple trails, estimate daily mileage, suggest campsites, calculate total elevation gain.
- Gear recommendations: Based on trail difficulty, weather, and distance, suggest what to bring. Beginners especially would benefit from "you'll want trekking poles for this one."
- Offline mode: Download trail maps and details for offline access. Cell service is spotty on most trails; having critical info cached would be invaluable.
The core insight here: people don't just need to find trails—they need help with the entire pre-adventure workflow. Permits, routes, gear, conditions, and social coordination are all friction points that technology could smooth out. The question is which problems to solve first and how to keep the experience simple rather than overwhelming.
Tech Stack
- Frontend: React + TypeScript + Vite
- Styling: Tailwind CSS with custom earth-tone palette
- Maps: Leaflet + OpenStreetMap tiles
- APIs: National Park Service (trail data), OpenRouteService (geocoding + routing)
- Database: Bolt Database (Supabase) with edge functions
- State Management: React hooks (useState, useEffect) + custom hooks for data fetching
Key Learnings
The biggest lesson: action beats anxiety. I went into this workshop intimidated by APIs I'd never used, worried about rate limits and error handling and authentication. But once I started making requests and seeing data come back, the mystery evaporated. APIs are just functions that happen to live on someone else's server.
The second lesson: constraints breed creativity. Having limited time and no budget forced smart tradeoffs. I couldn't use premium data sources or build complex features, so I focused ruthlessly on what mattered: helping people find trails they can actually get to, with safety information they actually need.
The third lesson: shipping is learning. I could have spent weeks researching the "right" way to build this. Instead, I built something imperfect in an evening and learned more from wrestling with real problems than I would have from any tutorial.