Không có mô tả

k4be b7fe59ba99 Don't auto-fit map after user manually pans or zooms 7 giờ trước cách đây
gpx-vis-backend d73f34ba6d Add track editing (name + type) with emoji labels 8 giờ trước cách đây
gpx-vis-frontend b7fe59ba99 Don't auto-fit map after user manually pans or zooms 7 giờ trước cách đây
sample 92ed699a57 Add sample GPX viewer and root gitignore 1 ngày trước cách đây
.gitignore 92ed699a57 Add sample GPX viewer and root gitignore 1 ngày trước cách đây
CLAUDE.md f345200b4c Add elevation profile chart and map hover tooltip 12 giờ trước cách đây
README.md e3dba8d542 Add folder tree browser, drag-drop move, folder zoom, and docs 12 giờ trước cách đây

README.md

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

git clone <repo-url>
cd gpx-vis

2. Install backend dependencies

cd gpx-vis-backend
npm install

3. Configure the backend

cp config.example.js config.js

Edit config.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:

database: {
  type: 'mariadb',   // or 'mysql'
  host: 'localhost',
  port: 3306,
  database: 'gpx_vis',
  username: 'gpxuser',
  password: 'secret',
},

4. Configure the frontend

cd ../gpx-vis-frontend
cp config.example.js config.js

Edit config.js:

window.APP_CONFIG = {
  apiUrl: 'https://your-domain.example.com/api-proxy',  // see nginx section below
  appName: 'GPX Visualizer',
};

5. Start the backend

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:

[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
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:

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):

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.

# Simple dev server for the frontend
cd gpx-vis-frontend
npx serve .

Running tests

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