Portlore is a cruise port guide for finding nearby places and planning a day ashore. It combines port and terminal data with curated OpenStreetMap POIs, Google Places matching, route estimates, and generated destination summaries.
Live site: https://portlore.com
- Search and browse port destinations
- View port and terminal locations on a map
- Explore attractions, food, shopping, and practical stops
- Compare walking and driving estimates
- Build an itinerary with visit and travel time
- Open matched locations in Google Maps
- Generate guides for ports that do not have one yet
client/ Static frontend
server/ Express API and generation routes
shared/ Shared POI, geocoding, and terminal logic
scripts/ Catalog and guide generation tools
cities/ports.json Current port catalog
cities/poi/ Curated POI catalogs
The frontend is currently contained in client/src/index.html and can be reworked into a more structured client later.
scripts/generate-ports.jscreates a broad candidate list from the World Port Index dataset.- Candidates are reviewed before being added to
cities/ports.json. scripts/build-all-poi-catalogs.jsdownloads the required OpenStreetMap extracts.scripts/build-poi-catalog.jsextracts nearby POI candidates for each port.- POIs are reviewed and saved in
cities/poi/. - Google Places matching adds Place IDs and terminal candidates.
- Anthropic is used for short destination descriptions and practical tips.
- The server calculates route, distance, and terminal access information.
Generated guides are stored as cities/<port-id>.json. They are runtime files and are not committed to Git.
The port list, cruise-port filtering, terminal records, and POI catalogs are still being refined.
The current cities/ports.json contains a manually reviewed working catalog, but it may still include unsuitable ports, miss valid cruise destinations, or combine terminals that should be treated separately.
Run the initial port candidate generator with:
node scripts/generate-ports.jsIt writes cities/port-candidates.json. This file is ignored by Git and does not replace cities/ports.json.
The generator only applies a broad physical-port filter. It does not confirm that a port currently receives passenger cruises.
Run the batch builder with:
node scripts/build-all-poi-catalogs.jsIt creates cities/osm-extracts.json, downloads the required .osm.pbf files, and builds local POI data. The manifest, raw extracts, and cities/poi-raw/ output are ignored by Git.
Validate the committed port and POI data with:
node scripts/validate-data.jsAudit nearby ports and possible ID issues with:
node scripts/audit-ports.jsRequirements:
- Node.js 20 or newer
- Anthropic API key
- Google Maps Platform key with Places and Routes access
- Pexels API key
Create the local environment file:
cp .env.example .envInstall dependencies:
cd server
npm install
cd ../scripts
npm installStart the API:
cd server
npm startServe client/src/ with a static web server on port 8080 to run the frontend locally.
Generate one guide:
node scripts/generate-city.js saint-john-canadaResolve Google Places data without generating the full guide:
node scripts/resolve-google-places.js saint-john-canadaProcess a small batch:
node scripts/resolve-google-places.js --all --limit=10Generated guides are written to cities/<port-id>.json. The source files in cities/poi/ are not changed.
Copy .env.deploy.example to .env.deploy and add the SSH target and remote directory.
Deploy with:
bash scripts/deploy.shThe script uploads the release, installs server dependencies, preserves existing generated guides, restarts Portlore with PM2, checks the health endpoint, and reloads Nginx.
Portlore is a planning tool. Opening hours, accessibility, transportation, terminal use, and cruise schedules can change. Travelers should confirm important details with official sources.
The scripts can rebuild new POI candidates from current OpenStreetMap data, but they cannot reproduce the committed catalogs exactly. The current catalogs include automated extraction, manual review, assisted curation, and later cleanup.
To remove a port from the project:
- Delete its entry from
cities/ports.json. - Delete its matching file from
cities/poi/. - Run
node scripts/validate-data.js. - Delete any old generated guide for that port from the server when appropriate.
Normal deployment preserves generated guides, so removed ports are not deleted from the server automatically.