# GPX Visualizer A self-hosted web application for uploading, organising, and visualising GPX tracks on an interactive map. ## Features - **Interactive map** — OpenStreetMap, topographic, and satellite base layers via Leaflet.js - **GPX upload** — drag files onto the map or use the upload button; multiple files at once - **Folder tree** — create nested folders, expand/collapse inline, drag tracks between folders - **Map zoom to folder** — clicking a folder loads all its tracks and zooms the map to fit - **Track info** — distance, point count, date shown in a floating panel - **Stats tab** — totals and per-month breakdown of distance and track count - **Share links** — generate a public URL for any track (no login required to view) - **User accounts** — JWT auth; first registered user becomes admin; admin activates subsequent users - **Admin panel** — activate/deactivate users, grant/revoke admin, delete users - **URL state** — map position, visible tracks, and open track are saved to the URL hash - **Database** — SQLite (default) or MySQL/MariaDB via Sequelize ORM ## Requirements - Node.js 18+ - npm - A web server to serve the frontend (nginx, Apache, Caddy, etc.) ## Installation ### 1. Clone the repository ```bash git clone cd gpx-vis ``` ### 2. Install backend dependencies ```bash cd gpx-vis-backend npm install ``` ### 3. Configure the backend ```bash cp config.example.js config.js ``` Edit `config.js`: ```js module.exports = { port: 3000, database: { type: 'sqlite', storage: './data/gpx-vis.db', // created automatically }, jwt: { secret: 'replace-with-a-long-random-string', expiresIn: '7d', }, upload: { maxFileSizeMB: 50, tempDir: './temp', }, cors: { origin: 'https://your-domain.example.com', // frontend origin }, }; ``` For MySQL/MariaDB replace the `database` block: ```js database: { type: 'mariadb', // or 'mysql' host: 'localhost', port: 3306, database: 'gpx_vis', username: 'gpxuser', password: 'secret', }, ``` ### 4. Configure the frontend ```bash cd ../gpx-vis-frontend cp config.example.js config.js ``` Edit `config.js`: ```js window.APP_CONFIG = { apiUrl: 'https://your-domain.example.com/api-proxy', // see nginx section below appName: 'GPX Visualizer', }; ``` ### 5. Start the backend ```bash cd ../gpx-vis-backend npm start ``` The database schema is created automatically on first run. To run as a system service, create `/etc/systemd/system/gpx-vis.service`: ```ini [Unit] Description=GPX Visualizer backend After=network.target [Service] Type=simple User=www-data WorkingDirectory=/opt/gpx-vis/gpx-vis-backend ExecStart=/usr/bin/node index.js Restart=on-failure Environment=NODE_ENV=production [Install] WantedBy=multi-user.target ``` ```bash systemctl enable --now gpx-vis ``` ### 6. Serve the frontend with nginx Copy `gpx-vis-frontend/` to your web root (e.g. `/var/www/gpx-vis`), then configure nginx: ```nginx server { listen 443 ssl; server_name your-domain.example.com; # SSL configuration (certbot / manual) ssl_certificate /etc/letsencrypt/live/your-domain.example.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/your-domain.example.com/privkey.pem; root /var/www/gpx-vis; index index.html; # Proxy /api/* to the Node.js backend location /api/ { proxy_pass http://127.0.0.1:3000; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; # Allow large GPX uploads client_max_body_size 55m; } # SPA fallback — all non-file paths serve index.html location / { try_files $uri $uri/ /index.html; } } # Redirect HTTP to HTTPS server { listen 80; server_name your-domain.example.com; return 301 https://$host$request_uri; } ``` With this setup, set `apiUrl` in the frontend config to the **same origin** (no separate port needed): ```js window.APP_CONFIG = { apiUrl: '', // empty string = same origin; requests go to /api/... appName: 'GPX Visualizer', }; ``` > **Note:** The backend `cors.origin` can be set to `''` or removed when the frontend and API share the same origin via the proxy. ### Running without nginx (development) Start the backend on port 3000 and open the frontend directly in a browser (via `file://` or a simple HTTP server). Set `apiUrl: 'http://localhost:3000'` in the frontend config. ```bash # Simple dev server for the frontend cd gpx-vis-frontend npx serve . ``` ## Running tests ```bash cd gpx-vis-backend npm test ``` Tests use an in-memory SQLite database and cover geo utilities, GPX processing, and the full REST API (56 tests). ## Project structure ``` gpx-vis/ ├── gpx-vis-backend/ │ ├── config.example.js │ ├── index.js │ └── src/ │ ├── middleware/auth.js │ ├── models/ (User, Directory, Track, TrackPoint, ShareLink) │ ├── routes/ (auth, directories, tracks, stats, share, admin) │ └── utils/ (geo, gpx-processor, shortcode) ├── gpx-vis-frontend/ │ ├── config.example.js │ ├── index.html │ ├── css/style.css │ └── js/ (api, auth, map, browser, stats, app) └── sample/ └── index.html (standalone viewer, no backend) ``` ## License MIT