Sign inSign up

monxas/trip-planner

By monxas

•Updated about 1 hour ago

Trip planner web app for group travel

Image
0

9.4K

monxas/trip-planner repository overview

⁠Trip Planner

Tests

A full-stack PWA for collaborative group trip planning. Built for a Japan 2026 trip but easily configurable for any destination.

⁠Features

Core

  • Multi-traveler support with colored avatars and per-traveler data
  • Real-time sync across devices via Server-Sent Events (SSE)
  • Token-based auth with read-only sharing (QR codes)
  • Guided onboarding flow (install → auth → create/join → flights → tutorial → traveler select)
  • Global search across all entities
  • PWA with offline support, install prompt, and network status indicator

Modules

  • Dashboard — Trip overview with countdown, quick actions, and activity feed
  • Places — Google Places integration (search, photos, details, notes, voting)
  • Map — Interactive Leaflet map with city/hotel segment filters, colored markers per category
  • Itinerary — Drag-and-drop scheduling (dnd-kit), accordion view, transit time indicators between events
  • Hotels — Reservations with chronological timeline
  • Flights — Search by flight number (FlightRadar24 scraping), auto-fill airline/airports/times
  • Translator — ~280 Japanese phrases with romaji, TTS, favorites; 3 tabs (quick access, categories, search)
  • Currency — EUR/JPY converter + historical exchange rate chart (fawazahmed0 API via jsDelivr)
  • Packing List — Per-traveler lists with categories
  • Calendar Export — Generate .ics files from itinerary
  • Push Notifications — VAPID/web-push with location-based proximity alerts

Infrastructure

  • 35+ REST API endpoints with CRUD factory pattern
  • Security: helmet + CSP, CORS, rate limiting, structured logging (pino)
  • SQLite backups (daily cron, 7-day retention)
  • Docker single-container deployment with healthcheck
  • CI/CD: GitHub Actions (lint + build) → webhook-based deploy

⁠Quick Start

⁠Development
# Frontend
npm install
npm run dev          # http://localhost:5173

# Backend (separate terminal)
cd server
npm install
npm start            # http://localhost:3001
⁠Docker
docker compose up -d

Or standalone:

docker run -d \
  -p 3001:3001 \
  -v trip-data:/app/server/data \
  monxas/trip-planner:latest

The container serves both the API and the built frontend on port 3001.
Healthcheck: GET /api/health

⁠Architecture

┌─────────────────────────────────┐
│  React 19 SPA (Vite 7 build)   │
│  TailwindCSS v4 + Lucide icons │
├─────────────────────────────────┤
│  Service Worker (vite-plugin-pwa)│
│  NetworkFirst: /api/*           │
│  CacheFirst: tiles, photos     │
├─────────────────────────────────┤
│  Express API (Node.js)          │
│  SSE for real-time sync         │
│  SQLite (better-sqlite3)        │
└─────────────────────────────────┘

Auth model: Trip tokens grant full access; read-only tokens allow viewing without modification. Tokens are shared via QR code or link.

⁠Testing

Enterprise-grade testing infrastructure with comprehensive coverage:

  • 953 tests across 78 test files
  • Coverage: Store 95%, Services 92%, Hooks 97%, Components 60%+
  • Framework: Vitest + React Testing Library + MSW
  • CI/CD: GitHub Actions runs all tests on every push
  • Bug prevention: Critical edge cases covered (e.g., empty arrays, network errors)
npm test              # Run all tests
npm run test:watch    # Watch mode
npm run test:coverage # Coverage report
npm run test:ci       # CI mode (verbose + coverage)

⁠Project Structure

src/
├── components/
│   ├── ui/            # Button, IconButton, Input, Select, Card, Badge, Toggle, Avatar
│   ├── map/           # CityFilterBar, FilterBar, MarkerPopup, icons, geocoding
│   ├── onboarding/    # InstallStep, AuthStep, CreateTrip, JoinTrip, Flights, Tutorial
│   ├── places/        # PlaceCard, PlaceDetails, PlaceNotes, PlaceSearch
│   ├── itinerary/     # AccordionView, EventCard, TransitIndicator, SortableEventCard
│   └── ...            # Dashboard, Hotels, Translator, PackingList, Settings
├── store/             # 6 modular stores (trip, places, events, hotels, flights, packing)
├── hooks/             # useCurrentLocation, useKeyboardVisible, useInstallPrompt, etc.
├── utils/             # transit.ts, ics.ts, distance.ts
└── services/          # API client

server/
├── index.js           # Express server + all routes
├── db.js              # SQLite setup + migrations
├── seed.js            # Initial data
├── scripts/           # backup-db.sh (daily cron, 7-day retention)
└── .env               # VAPID keys, Google API key, config

⁠Environment Variables

Server (server/.env)

VariableDescription
PORTServer port (default: 3001)
VAPID_PUBLIC_KEYWeb push public key
VAPID_PRIVATE_KEYWeb push private key
VAPID_EMAILContact email for VAPID
GOOGLE_PLACES_API_KEYGoogle Places API key

Frontend (compile-time via Vite)

VariableDescription
VITE_API_URLBackend URL (default: same origin)
VITE_VAPID_PUBLIC_KEYWeb push public key (client-side)

⁠CI/CD

  • CI: Every push and PR runs lint + build via GitHub Actions (ci.yml)
  • Deploy: Push to master triggers a GitHub webhook → deploy-webhook container on the media server pulls, builds, and deploys the Docker container automatically

No SSH keys or self-hosted runners involved.

⁠Tech Stack

LayerTechnology
FrontendReact 19, TypeScript 5.9, Vite 7, TailwindCSS v4
UILucide icons, dnd-kit, Leaflet + react-leaflet, QR code generation
BackendNode.js, Express, better-sqlite3, web-push
Real-timeServer-Sent Events (SSE)
PWAvite-plugin-pwa, Workbox strategies
External APIsGoogle Places, FlightRadar24 (scraping), fawazahmed0/exchange-api
InfraDocker, GitHub Actions

⁠Design Decisions

⁠No budget/expense tracking

Intentionally omitted. Dedicated apps do this better:

Keeping the app focused on planning, not accounting.


MIT License

Tag summary

Content type

Image

Digest

sha256:217774c57…

Size

140.7 MB

Last updated

about 1 hour ago

docker pull monxas/trip-planner