AI-powered collaborative trip planning with activity voting, auto itinerary scheduling, and map visualization.
- Email/password authentication with secure cookie sessions
- Per-trip access control (owner/viewer) with sharing by email
- AI activity generation for places and food based on traveler preferences
- Approve/reject flow for collaborative decision making
- Automatic day-by-day itinerary construction from approved activities
- Google Maps map view with place search + POI click-to-add (beta), plus legacy Leaflet fallback
- Per-traveler preferences (likes, dislikes, budget)
| Layer | Technology |
|---|---|
| Framework | Next.js 15 (App Router, TypeScript) |
| Styling | Tailwind CSS |
| Database | SQLite via Prisma ORM + better-sqlite3 adapter |
| LLM | OpenAI gpt-5-mini (default), Azure OpenAI / Bifrost optional |
| Map | Google Maps JavaScript API (+ Places), Leaflet/OpenStreetMap fallback |
| Testing | Jest + Testing Library |
npm installcp .env.example .env
# Set OPENAI_API_KEY=...Optional: override model for non-Azure OpenAI.
OPENAI_MODEL=gpt-5-miniOptional: enable Google Maps picker (frontend) and Google Maps Geocoding (backend).
GOOGLE_MAPS_API_KEY=your-google-maps-keyOptional: use Azure OpenAI instead of standard OpenAI.
AZURE_OPENAI_API_KEY=your-azure-key
AZURE_OPENAI_ENDPOINT=https://<resource-name>.openai.azure.com/
AZURE_OPENAI_DEPLOYMENT=your-deployment-name
AZURE_OPENAI_API_VERSION=2025-01-01-previewOptional: use Bifrost OpenAI-compatible API provider.
LLM_PROVIDER=bifrost
BIFROST_BASE_URL=http://127.0.0.1:8080
# BIFROST_API_KEY=optional-api-keyBehavior:
- If
LLM_PROVIDERis set (openai,azure,bifrost), that provider is used. - Without
LLM_PROVIDER, provider auto-detection is used in this order: OpenAI (OPENAI_API_KEY) → Azure (AZURE_OPENAI_API_KEY) → Bifrost (BIFROST_BASE_URLorBIFROST_API_KEY). - Bifrost uses OpenAI-compatible API calls via
BIFROST_BASE_URL. BIFROST_BASE_URLaccepts host-only values (for examplehttp://192.168.1.200:8080) and is normalized to/openai/v1.- If
BIFROST_BASE_URLis not set, default ishttp://127.0.0.1:8080/openai/v1. BIFROST_API_KEYis optional and defaults to an empty string when unset.- Bifrost model selection uses
OPENAI_MODEL(defaultgpt-5-mini). - Activity
lat/lngand Google Maps map picker useGOOGLE_MAPS_API_KEYwhen set.
Provider-specific error handling:
- Bifrost auth errors (
401/403) return a clearBIFROST_API_KEYmessage. - Bifrost endpoint errors (
404, connection failures) return a clearBIFROST_BASE_URL/network message. - Bifrost rate-limit and server errors (
429,5xx) return retry-oriented messages.
npx prisma migrate dev
npx prisma generatenpm run devOpen http://localhost:9527.
- Register/login at
/auth - All pages and APIs require authentication except
/authand/api/auth/* - Trip sharing supports
owner -> viewerby email:owner: full read/write + delete/shareviewer: read-only
- Legacy endpoints are deprecated:
/api/users/api/users/[id]/preferences- Use
/api/meand/api/me/preferencesinstead
Primary endpoints use activities naming:
GET/POST /api/trips/[id]/activitiesPOST /api/trips/[id]/activities/fillPATCH/DELETE /api/activities/[id]POST /api/activities/[id]/approvePOST /api/activities/[id]/reject
Legacy activity-route aliases are removed.
npm run dev # Start development server
npm run build # Production build
npm run start # Start production server
npm run lint # ESLint
npm run test # Jest
npm run test:ci # Jest (CI mode + coverage)
npm run test:e2e # Playwright end-to-end testsBefore running Playwright E2E for the first time:
npx playwright install chromiumGitHub Actions workflow (.github/workflows/ci.yml) runs:
npm cinpx prisma generatenpm run lintnpm run test:cinpm run build(with placeholderOPENAI_API_KEY)
Run equivalent checks locally:
just cisrc/
app/
page.tsx # Home – list & create trips
trips/[id]/page.tsx # Trip detail (Activities / Itinerary / Map tabs)
trips/[id]/preferences/ # Per-traveler preference management
api/ # REST API routes
trips/ # CRUD for trips
activities/[id]/approve|reject
users/ # CRUD for users & preferences
components/
GoogleMapView.tsx # Google Maps place picker + map markers
ActivityCard.tsx # Activity card with approve/reject buttons
ItineraryView.tsx # Day-by-day itinerary grouped by time block
MapView.tsx # Leaflet map (client-only)
TripCard.tsx # Trip summary card
lib/
prisma.ts # Prisma client singleton
llm.ts # OpenAI/Azure OpenAI activity generation
prisma/
schema.prisma # Data model
| Entity | Key fields |
|---|---|
Trip |
name, cities (JSON array) |
User |
name |
Preference |
userId, likes, dislikes, budget |
Activity |
tripId, type, title, description, reason, lat/lng, city, suggestedTime, durationMinutes, status |
ItineraryItem |
tripId, activityId, day, timeBlock (morning/afternoon/dinner) |
A demo preview page is deployed to GitHub Pages on every push to main via .github/workflows/deploy-pages.yml.
- Preview URL: https://nationalteam.github.io/trip-planner/
- Manual deploy: run Deploy demo site to GitHub Pages in GitHub Actions
cp .env.example .env
# Set OPENAI_API_KEY or AZURE_OPENAI_* variables
docker compose up --buildOpen http://localhost:9527.