# NatureHub: National Park Explorer

NatureHub is a no-build portfolio web application for discovering U.S. National
Park Service places, reviewing practical visit information, checking a short
weather outlook, locating a park on a map, saving favorites, and making a simple
personal trip plan.

It is designed for PHP 8+ shared hosting, including a subdirectory on GoDaddy.
There is no Node.js dependency, package manager, framework, account system, or
database.

> NatureHub is an independent educational portfolio project. It is not
> affiliated with or endorsed by the National Park Service.

## Features

- Responsive single-page navigation with browser history through hash routes
- Park search by keyword and state
- Client-side designation filtering, alphabetical sorting, and load-more paging
- Detailed park descriptions, directions, addresses, hours, fees, contacts,
  activities, topics, official links, and active NPS alerts when provided
- Open-Meteo current conditions and five-day forecast in Fahrenheit and mph
- Leaflet map with OpenStreetMap tiles, a marker, attribution, and text fallback
- Device-local favorites with duplicate prevention and clear-all confirmation
- Five-item recently viewed history
- Device-local trip planner with dates, validation, notes, editable checklist,
  completion states, removal, clear-all confirmation, and print layout
- Light and dark themes that respect `prefers-color-scheme`
- Expiring session cache, debounced search, stale-request cancellation, lazy
  images, and duplicate-request protection
- Explicit opt-in demo mode with a visible **Demo Data** label
- Plain-language loading, empty, invalid-response, timeout, rate-limit, storage,
  map, weather, and general network states

## Screenshots

Add portfolio screenshots after deployment:

1. `docs/screenshots/home-desktop.jpg` — home dashboard, desktop
2. `docs/screenshots/explore-mobile.jpg` — filtered results, narrow viewport
3. `docs/screenshots/park-detail-dark.jpg` — detail view, dark theme
4. `docs/screenshots/trip-planner.jpg` — planner and checklist

Update the Open Graph image placeholder in `index.html` at the same time.

## Technologies

- Semantic HTML5
- Modern mobile-first CSS, custom properties, Grid, Flexbox, and `clamp()`
- Vanilla JavaScript ES6 modules, Fetch API, async/await, AbortController
- PHP 8+ server-side API proxy
- Browser `localStorage` and `sessionStorage`
- Leaflet 1.9.4

No compilation or build step is required.

## APIs and attribution

- [National Park Service Developer API](https://www.nps.gov/subjects/developer/)
  supplies park and alert data. Live calls are made only by the local PHP proxy.
- [Open-Meteo](https://open-meteo.com/) supplies forecast data and does not
  require a public key for this use.
- [OpenStreetMap](https://www.openstreetmap.org/copyright) supplies map tiles.
  Required attribution appears on every Leaflet map.

NPS records vary by place. NatureHub hides sections when an address, image, fee,
contact, coordinate, alert, activity, or other field is absent.

## Project structure

```text
natureHub/
├── index.html
├── start-naturehub.bat
├── .htaccess
├── .gitignore
├── README.md
├── TESTING.md
├── api/
│   ├── .htaccess
│   ├── alerts.php
│   ├── bootstrap.php
│   ├── config.example.php
│   ├── park-details.php
│   └── parks.php
└── assets/
    ├── css/
    │   ├── reset.css
    │   ├── variables.css
    │   ├── base.css
    │   ├── components.css
    │   ├── layouts.css
    │   ├── utilities.css
    │   └── print.css
    ├── data/
    │   └── demo-parks.json
    ├── icons/
    │   └── favicon.svg
    ├── images/
    │   └── naturehub-wilderness.png
    └── js/
        ├── api.js
        ├── app.js
        ├── favorites.js
        ├── map.js
        ├── parks.js
        ├── planner.js
        ├── router.js
        ├── storage.js
        ├── ui.js
        ├── utils.js
        └── weather.js
```

## Local setup

### Requirements

- PHP 8.0 or newer
- PHP cURL extension, strongly recommended
- A modern browser with JavaScript modules
- An NPS API key for live park data

Opening `index.html` directly from the file system shows a useful static project
preview, including bundled artwork and feature descriptions. Interactive search,
maps, weather, storage features, and PHP endpoints still require a web server
because browsers restrict ES modules on `file://` URLs.

### 1. Obtain an NPS API key

Request a key from the
[NPS developer portal](https://www.nps.gov/subjects/developer/get-started.htm).
Never paste the key into HTML, JavaScript, screenshots, a Git commit, or a public
issue.

### 2. Create the private configuration

For local development only:

1. Copy `api/config.example.php` to `api/config.php`.
2. Replace `REPLACE_WITH_YOUR_NPS_API_KEY`.
3. Keep `api/config.php` uncommitted. It is already listed in `.gitignore`.

The preferred production setup places the configuration outside `public_html`:

```text
/home/account/naturehub-private/config.php
/home/account/public_html/internshipExamples/natureHub/
```

The proxy automatically checks `naturehub-private/config.php` beside the
document root. It also supports the `NPS_API_KEY` environment variable and a
custom absolute file path in `NATUREHUB_CONFIG_PATH`.

### 3. Start a local server

On Windows, double-click `start-naturehub.bat` for a guided demo-mode preview.
It checks for PHP, starts the local server, and opens NatureHub in the browser.

Or start the server manually from the `natureHub` directory:

```bash
php -S localhost:8000
```

Open `http://localhost:8000/`.

Test a proxy endpoint directly:

```text
http://localhost:8000/api/parks.php?limit=1&start=0
```

A successful response contains `data` and `total`. A missing key produces a
safe `503` JSON error and never includes the secret.

### Demo mode

Demo mode is intentional and visibly labeled:

- Visit `http://localhost:8000/?demo=1`, or
- Open **About** and choose **Use demo data**.

Disable it from About or use `?demo=0`. The choice is stored in this browser.
The eight records in `assets/data/demo-parks.json` are a UI demonstration, not
live data. Weather and OpenStreetMap remain live when reachable.

## GoDaddy deployment

This project uses relative asset and endpoint paths. It can be uploaded to:

```text
public_html/internshipExamples/natureHub/
```

No domain-root assumptions or rewrite-based SPA fallback are required because
client routes use URL hashes such as `#/explore` and `#/park/yell`.

### Deployment checklist

1. Upload the contents of `natureHub` to the selected `public_html` subdirectory.
2. Create `/home/account/naturehub-private/config.php` from
   `api/config.example.php` when the account layout permits it.
3. Add the real NPS API key to that private file.
4. In the GoDaddy control panel, confirm PHP 8.0 or newer and enable cURL.
5. Open `api/parks.php?limit=1&start=0` over HTTPS and confirm valid JSON.
6. Open the app and verify CSS, JavaScript, the favicon, and demo JSON use the
   correct relative subdirectory paths.
7. Confirm the domain has a valid HTTPS certificate. Optionally enable the
   commented HTTPS redirect in `.htaccess` afterward.
8. Test home, Explore, one park, Favorites, and Planner on a phone.
9. Navigate the full interface with Tab, Shift+Tab, Enter, Space, and Escape.
10. Request `api/config.php` and `api/config.example.php` in a private browser.
    The server must return `403` (or another denial), never PHP source or a key.
11. Replace the canonical URL and Open Graph placeholders in `index.html` with
    the final HTTPS URL, and add a real social preview image.
12. Verify that `.git`, `.env`, local logs, and `api/config.php` were not
    uploaded from an unsafe source.

Some shared-hosting plans disallow individual Apache directives. If an upload
produces an HTTP 500 error, consult GoDaddy’s current Apache configuration and
remove only the unsupported optional compression or expiration block. Keep the
config protection and security headers.

## Security approach

- The NPS key is added only by PHP and never returned to the browser.
- The proxy has a hardcoded base URL and endpoint allowlist (`parks`, `alerts`);
  a visitor cannot supply a URL, protocol, hostname, or arbitrary endpoint.
- Only GET requests are accepted.
- Each input has a type, pattern, length, and numeric range.
- Search result sizes and offsets are bounded.
- Connections use TLS verification, conservative connect/total timeouts, no
  redirects, and a fixed user agent.
- Upstream content must decode as JSON with a `data` array.
- Public errors use safe messages; transport details go only to server logs.
- `.htaccess` denies config and common sensitive files, disables indexing, and
  sets a Content Security Policy and defensive browser headers.
- Dynamic NPS content is inserted with DOM methods and `textContent`. External
  URLs are limited to HTTP(S) and receive `target="_blank"` plus
  `rel="noopener noreferrer"`.

When `api/config.php` must live inside the project, both `.gitignore` and the
API-level `.htaccess` protect it. A file outside `public_html` is still safer.

## Data storage and privacy

The browser stores only:

- compact favorite park summaries
- five compact recent park summaries
- trip park summaries, dates, notes, and checklist items
- theme and demo-mode preferences

There is no account or server database. Data does not sync across devices and
is removed when the user clears this site’s browser data. Suitable API
responses use expiring `sessionStorage` entries (five minutes for park searches
and alerts, ten minutes for a park detail, fifteen minutes for weather).

## Accessibility

The interface targets WCAG 2.2 AA practices:

- skip link and semantic header, navigation, main, sections, articles, aside,
  footer, forms, lists, descriptions, and headings
- one page-level heading per rendered view and logical section headings
- native controls with visible high-contrast focus rings
- keyboard-accessible mobile navigation with `aria-expanded` and Escape support
- programmatic labels and park-specific accessible names
- `aria-pressed` favorite state and status/error live regions
- meaningful image alternatives and designed missing-image fallbacks
- text alternative for every map location
- errors that explain recovery without raw exception text
- reduced motion support and layouts that remain usable around 320 CSS pixels
- color is reinforced by words, icons, borders, or state text
- dark and light theme contrast tokens
- print styles that retain planner content

Use `TESTING.md` for manual keyboard, zoom, high contrast, and assistive
technology checks on the final hosting environment.

## Performance notes

- Park card images are lazy-loaded with dimensions and asynchronous decoding.
- Search input updates are debounced by 450 ms.
- An `AbortController` cancels stale view and search requests.
- Safe requests are cached temporarily in `sessionStorage`.
- Identical non-cancellable requests share one in-flight promise.
- Weather is requested only after a detail view with valid coordinates opens.
- A prior Leaflet map is destroyed before another is created.
- CSS and JavaScript are small, static, and require no runtime framework.
- Apache compression and cache headers are enabled when their modules exist.

## Manual testing

Run every item in `TESTING.md` against:

- local PHP server with demo mode
- local or staging server with a live NPS key
- the final subdirectory URL over HTTPS
- narrow mobile, tablet, and desktop widths
- 200% browser zoom
- keyboard-only navigation and at least one screen reader

PHP and JavaScript syntax checks are useful but do not replace browser,
assistive-technology, network-failure, and hosting checks.

## Known limitations

- NPS data quality and field availability vary by place.
- Designation filtering applies to records currently loaded in the browser,
  because the NPS parks endpoint does not provide a reliable server-side
  designation filter.
- Open-Meteo forecasts are coordinate-based and may not represent rapid
  elevation or microclimate changes.
- NPS alerts and official sources always take precedence over this app.
- OpenStreetMap tiles and Leaflet are loaded from third-party services and need
  a network connection.
- Demo images are illustrative licensed remote photographs and are not asserted
  to depict the named parks.
- Browser storage is local to one browser profile and can be cleared by the
  visitor.
- Hash routing gives reliable subdirectory behavior but does not provide a
  unique server-rendered page for each park.
- The PHP built-in server does not interpret `.htaccess`; config denial must be
  verified on Apache before production launch.

## Future enhancements

- Opt-in geolocation and distance sorting
- Accessible comparison view for selected parks
- Offline-ready cached trip summaries
- Export/import of a trip plan as a local JSON file
- NPS campground and visitor-center data
- Automated accessibility and cross-browser checks in continuous integration

## Credits

- Park and alert data: National Park Service
- Forecast data: Open-Meteo
- Map library: Leaflet
- Map data and tiles: OpenStreetMap contributors
- Demo photographs: Unsplash source URLs embedded in the labeled sample data

Review each provider’s current terms and attribution requirements before a
public launch.
