4.2 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
What This Project Is
Line of Sight is a geospatial web app that draws a great-circle line from a user-selected point on Earth in a chosen direction, then finds all cities along that path. It includes a flight-over animation that speeds up 20x over water and slows to normal speed over land.
Commands
Docker (preferred workflow)
docker-compose up --build # Start all services (frontend :3050, backend :3001, postgres)
docker-compose down # Stop all services
docker-compose logs -f # View logs
# Run tests inside containers
docker-compose exec backend npm test
docker-compose exec frontend npm test -- --run
docker-compose exec frontend npm run test:e2e
Local development (without Docker)
# Backend
cd backend && npm run dev # Nodemon dev server on :3001
# Frontend
cd frontend && npm run start # Vite dev server on :3050
Tests
# Backend unit tests (Jest + Supertest)
cd backend && npm test
# Frontend unit tests (Vitest)
cd frontend && npm test # Watch mode
cd frontend && npm test -- --run # Single run (CI mode)
# E2E tests (Playwright)
cd frontend && npm run test:e2e
# Seed the database with GeoNames city data
cd backend && npm run seed-data
Build
cd frontend && npm run build # Vite production build → frontend/build/
Architecture
This is a monorepo with three services orchestrated by Docker Compose:
frontend/ → React 19 + Vite 6 SPA (MapLibre GL, Turf.js, Axios)
backend/ → Node 24 + Express 5 REST API
docker/ → PostgreSQL + PostGIS initialization
Data flow
- User clicks map → sets start point (lat/lon)
- User selects direction (0–360°) and tolerance (km radius)
- Frontend calls
GET /api/line-of-sight?lat=&lon=&direction=&tolerance= - Backend generates 80 path points along a great-circle arc (up to 20,000 km)
- For each point, a PostGIS
ST_DWithin()query finds cities within tolerance - Backend also checks whether each point is over land (500 km radius land check)
- Response includes line coordinates with per-point water flags and matching cities
- Frontend renders the path on a 3D globe map and shows city markers
Backend: backend/app/server.js
Single-file Express app. Key internals:
calculateDestination()— Haversine formula for great-circle destination pointsGET /api/line-of-sight— main endpoint: path generation + PostGIS city lookupGET /api/health— health check- Returns up to 200 cities ordered by position along the line
Frontend: frontend/src/App.jsx
Single large React component (~687 lines) managing all state and map logic:
- MapLibre GL map with 3D globe projection and terrain/sky effects
- Direction slider drives a live preview line before the user commits
- After "Show Line of Sight", map locks (prevents moving start point)
- Flight animation uses Turf.js to interpolate positions along the path; speed is 1× over land, 20× over water with smooth acceleration (0.005 step), predictive look-ahead of 2000 km
- New cities are fetched every 2000 km during flight via the same API
- Three map styles: light, dark, satellite (Esri tiles)
Database
PostGIS cities table with a GIST index on geom GEOGRAPHY(POINT, 4326). All coordinates use WGS84 / SRID 4326. The init SQL seeds 10 major cities; the seed-data script imports from GeoNames for a fuller dataset.
Conventions
- Geospatial: WGS84 / SRID 4326 everywhere; PostGIS
GEOGRAPHYtype for distance queries - API: RESTful; query params for
GET /api/line-of-sight; env varVITE_API_URL(frontend) orDATABASE_URL(backend) - Styling: Plain CSS files in
frontend/src/styles/— no CSS framework - Tests: Backend mocks the
pgPool; frontend mocks MapLibre GL and the API service. E2E tests use Playwright with a mock API response
CI
Gitea workflow (.gitea/workflows/test.yml) runs on push/PR to main:
- backend-test —
npm ci && npm test - frontend-test —
npm ci && npm test -- --run - e2e-test — uses
mcr.microsoft.com/playwright:v1.50.1container