An AI-powered road trip planner that builds a personalised day-by-day travel guide through an interactive, multi-agent conversation with Claude.
- Overview
- Features
- Quick Start
- Architecture
- AI Agents
- API Reference
- Using the App
- Local Development
- Configuration
- Project Structure
- Releases
- License
DetourAI lets you plan a complete road trip in minutes. You describe where you want to go and what matters to you; ten specialised Claude agents then collaboratively research the route, stops, accommodations, activities, restaurants, and driving schedule — and hand you back a structured, budget-aware travel guide.
flowchart TD
M["Modus wählen"] --> R["Roadtrip\n5-Schritte-Formular"]
M --> X["Erkunden\n5-Schritte-Formular\n+ Zonen-Karte"]
M --> O["Ortsreise\n1 Ort · Tage · Budget"]
R --> B["Login / Register"]
X --> B
O --> B
B --> C["RegionPlannerAgent\nplant Regionen — du bestätigst"]
C --> D["Stop-Optionen pro Segment\n(DetourOptionsAgent bei kurzen Segmenten)\n(ExploreZoneAgent bei Explore-Legs)"]
D --> E["3 Unterkunfts-Optionen pro Stop\n(Budget · Komfort · Premium)"]
E --> F["9 Agenten recherchieren\nAktivitäten · Restaurants · Tagesplan · Guide"]
F --> G["Reiseführer\nHorizontale Karte mit Hotel-/Aktivitäts-Pins\nÜbersicht · Stops · Tagesplan · Budget\n+ PDF · PPTX"]
- Three trip modes — Roadtrip (A→B transit), Erkunden (zone exploration), Ortsreise (single location)
- Leg-based trip architecture — build trips from Transit legs (A → B routing) and Explore legs (discover a geographic zone)
- Ortsreise mode — plan a multi-day stay at a single location with a dedicated single-step form
- Interactive route building — Claude suggests stops segment by segment; you pick the ones you want
- Explore mode — define a zone on the map and let ExploreZoneAgent discover anchor points, scenic spots, and hidden gems via a guided questionnaire
- Region planning — RegionPlannerAgent autonomously plans multi-region sequences after route confirmation
- Geometry-aware stop placement — OSRM measures the full remaining distance; stops are placed evenly along the route
- Detour fallback — when a segment is too short for classic stops, DetourOptionsAgent proposes scenic side-trips
- "Direkt weiterfahren" option — skip a stop and add freed nights to the next destination
- Rundkurs display — explore legs show a circular route through discovered stops
- Form persistence — form state saved to localStorage; survives page refresh
- Only real towns — StopOptionsFinder always returns concrete towns/cities, never regions
- Drive-limit enforcement — OSRM-verified drive times; options exceeding the limit get a warning badge
- Route-adjust modal — when all options exceed the limit, one click adds days or inserts a via-point
- Configurable proximity filter — set minimum distance from start/target to prevent stop bunching
- Real driving times — OSRM replaces AI estimates with actual road distances
- JWT-based authentication — secure login/register with Argon2id password hashing
- Admin panel — full user management UI for creating, editing, and deleting users
- Token quota per user — configurable daily token limit with enforcement and inline error messages
- Pre-flight token estimation — estimates job cost before starting; blocks if quota would be exceeded
- Parallel accommodation research — budget / comfort / premium options per stop loaded simultaneously
- Configurable budget split — set % allocation for accommodation, food, and activities with live CHF preview
- Budget tracking — remaining budget updates live after every accommodation selection
- 10 specialised AI agents — pre-planner, route architect, region planner, stop finder, detour finder, explore zone, accommodation researcher, activities, restaurants, day planner, travel guide, trip analysis
- Real-time progress — Server-Sent Events stream every agent action to the browser
- Live progress overlay — unified overlay with spinner log and green checkmarks during all wait phases
- Horizontal collapsible map — full-width map strip above the guide content; collapse/expand toggle; sticky on mobile
- Hotel & activity pins on main map — hotel (🏨) and activity emoji pins alongside numbered stop markers, loaded async with session-cached coordinate resolution
- Marker filter pills — toggle Stopps / Hotels / Aktivitäten visibility independently
- Interactive day maps — route polylines connecting all stops per day
- POI markers — accommodation, restaurant, and activity pins on each day map
- Google Places details — photos, opening hours, and ratings via Google Places API
- Travel guide with 4 tabs — overview map, stops & details, day-by-day plan, budget breakdown
- Export — download as PDF or PPTX
- Trip analysis — AI-powered post-planning analysis with requirement tags and keyword highlighting
- Saved trips — SQLite persistence with rename, star rating (0–5), replan, and delete
- Replace stop — swap out any stop in a saved trip and re-run research for the new destination
- Resume — browser-local state so you can pick up where you left off
- File-based logging — daily rotating log files in
backend/logs/with 30-day retention - Per-component log files — separate log files for each agent and backend component
- Token tracking per agent — token usage persisted per-job and rolled up to user quotas
- Frontend error reporting —
window.onerrorand unhandled rejections auto-reported to backend
- Travel-Forward design — sky-blue + adventure-orange branded UI with animated pastel background
- Lucide SVG icons — no emoji, consistent icon set throughout
- Full accessibility — focus rings, aria labels, screen-reader compatibility, keyboard navigation
- Mobile-responsive — dynamic viewport height, visible step labels on small screens
- Collapsible stops — sidebar navigation and calendar tab in the travel guide
- Google Maps integration — Places API photos, interactive maps, photo strips with lightbox
- Docker Desktop >= 24
- An Anthropic API key
git clone https://github.com/stefanschaedeli/DetourAI.git
cd DetourAI
cp backend/.env.example backend/.envEdit backend/.env:
ANTHROPIC_API_KEY=sk-ant-... # required
TEST_MODE=true # true = cheap haiku; false = opus/sonnet
REDIS_URL=redis://redis:6379
JWT_SECRET=your-secret-here # required for authdocker compose up --build| Container | Role | Port |
|---|---|---|
redis |
Job state store | 6379 (internal) |
backend |
FastAPI app | 8000 (internal) |
celery |
Background workers | — |
frontend |
Nginx + static files | 80 |
Navigate to http://localhost
docker compose down # stop everything
docker compose logs -f backend # follow backend logsflowchart TD
subgraph Browser["Browser (Vanilla JS, no build step)"]
UI["Auth → 5-step form → region confirm\n→ route builder → acc grid → guide tabs"]
end
Browser -- "HTTP + SSE" --> Nginx["Nginx (reverse proxy)"]
Nginx --> FastAPI
subgraph FastAPI["FastAPI Backend"]
JWT["JWT Middleware"]
JWT --> Orchestrator
subgraph Orchestrator["TravelPlannerOrchestrator"]
A0["ArchitectPrePlanAgent (sonnet)"]
A1["RouteArchitectAgent (opus)"]
A2["RegionPlannerAgent (opus)"]
A3["StopOptionsFinderAgent (sonnet)"]
A4["DetourOptionsAgent (haiku)"]
A5["ExploreZoneAgent (sonnet)"]
A6["AccommodationResearcher (sonnet)"]
A7["ActivitiesAgent (sonnet)"]
A8["RestaurantsAgent (sonnet)"]
A9["DayPlannerAgent (opus)"]
A10["TravelGuideAgent (sonnet)"]
A11["TripAnalysisAgent (sonnet)"]
end
end
FastAPI --> Redis["Redis (job state, 24h TTL)"]
FastAPI --> Celery["Celery Workers"]
Celery --> Redis
| Layer | Technology |
|---|---|
| Backend | Python 3.11, FastAPI, Pydantic v2 |
| Frontend | Vanilla JS (ES2020), HTML5, CSS3 |
| Real-time | Server-Sent Events (sse-starlette) |
| Job queue | Redis + Celery |
| AI | Anthropic SDK — 10 Claude agents |
| Auth | Argon2id (passlib) + JWT (python-jose) |
| Maps | Google Maps JS SDK + Places API |
| Routing | OSRM (open-source road routing) |
| Geocoding | OpenStreetMap Nominatim |
| Icons | Lucide SVG |
| Export | fpdf2 (PDF), python-pptx (PPTX) |
| Infra | Docker Compose, Nginx |
| Store | Technology | Lifetime | Content |
|---|---|---|---|
| Job state | Redis | 24h TTL | Live planning sessions, SSE queues, agent results |
| Travel history | SQLite (data/travels.db) |
Permanent | Saved trips with metadata and full plan JSON |
| Auth DB | SQLite (data/auth.db) |
Permanent | Users, refresh tokens, migrations |
DetourAI uses ten specialised Claude agents. Each has a single, clearly scoped task, communicates exclusively via structured JSON, and is orchestrated by TravelPlannerOrchestrator.
| Agent | Production | TEST_MODE=true |
|---|---|---|
| ArchitectPrePlanAgent | claude-sonnet-4-5 | claude-haiku-4-5 |
| RouteArchitectAgent | claude-opus-4-5 | claude-haiku-4-5 |
| RegionPlannerAgent | claude-opus-4-5 | claude-haiku-4-5 |
| StopOptionsFinderAgent | claude-sonnet-4-5 | claude-haiku-4-5 |
| DetourOptionsAgent | claude-haiku-4-5 | claude-haiku-4-5 |
| ExploreZoneAgent | claude-sonnet-4-5 | claude-haiku-4-5 |
| AccommodationResearcherAgent | claude-sonnet-4-5 | claude-haiku-4-5 |
| ActivitiesAgent | claude-sonnet-4-5 | claude-haiku-4-5 |
| RestaurantsAgent | claude-sonnet-4-5 | claude-haiku-4-5 |
| DayPlannerAgent | claude-opus-4-5 | claude-haiku-4-5 |
| TravelGuideAgent | claude-sonnet-4-5 | claude-haiku-4-5 |
| TripAnalysisAgent | claude-sonnet-4-5 | claude-haiku-4-5 |
ArchitectPrePlanAgent (claude-sonnet-4-5) — Generates a region overview before full route architecture, giving RouteArchitectAgent richer context for stop placement decisions.
RouteArchitectAgent (claude-opus-4-5) — Analyses the full trip and produces a high-level multi-segment route plan: which cities to pass through, how many days per segment, and the logical order of all waypoints. Uses Opus for its ability to reason across the entire trip simultaneously.
RegionPlannerAgent (claude-opus-4-5) — Analyses all confirmed legs and plans a region sequence: which stops belong to which region, how many nights per region, and the logical region order. Runs immediately after RouteArchitect and before StopOptionsFinder. The user reviews and confirms the region plan before stop selection begins.
StopOptionsFinderAgent (claude-sonnet-4-5) — For each route segment, proposes 3 stop options: direct (shortest path), scenic (landscape-first), and cultural (historically interesting). In explore mode, types become anker (anchor point), landschaft (scenic), and geheimtipp (hidden gem). Streams partial JSON so cards appear incrementally. All options are OSRM-enriched with real drive times.
DetourOptionsAgent (claude-haiku-4-5) — Fallback agent for segments too short for classic stops. Proposes 3 deliberate side-trip destinations off the direct route. No proximity filter applied — detours may be close to departure. Always uses Haiku as it is a lightweight fallback.
ExploreZoneAgent (claude-sonnet-4-5) — Two-pass workflow for explore legs. First pass: generates clarifying questions about the user's interests for the zone. Second pass: uses the answers to discover stops categorised as anchor points, scenic spots, and hidden gems within the defined zone bbox.
AccommodationResearcherAgent (claude-sonnet-4-5) — Finds 3 accommodation options per stop at budget / comfort / premium tiers. Type matches user preference (hotel, camping, hostel, apartment, Airbnb). Tracks remaining budget across all stops.
ActivitiesAgent (claude-sonnet-4-5) — Researches activities and attractions per stop, tailored to travel styles and group composition. Wikipedia enrichment adds cultural context for the day planner.
RestaurantsAgent (claude-sonnet-4-5) — Recommends restaurants per stop matching travel styles and food budget, with cuisine type, price range, and a recommended dish.
DayPlannerAgent (claude-opus-4-5) — Assembles the day-by-day travel plan from all agent outputs: schedules driving legs, distributes activities, ensures rest days, and writes narrative summaries. Uses Opus for cross-trip reasoning.
TravelGuideAgent (claude-sonnet-4-5) — Generates a narrative travel guide with storytelling descriptions for each stop and day. Radius-limited to stay within the confirmed travel area.
TripAnalysisAgent (claude-sonnet-4-5) — Post-planning analysis that evaluates how well the generated plan meets the original requirements, with requirement tags and keyword highlighting.
| Method | Path | Description |
|---|---|---|
POST |
/api/plan-trip |
Submit form, receive first stop options |
POST |
/api/select-stop/{job_id} |
Choose a stop, receive next options |
POST |
/api/recompute-options/{job_id} |
Re-run StopOptionsFinder with custom instructions |
POST |
/api/patch-job/{job_id} |
Adjust job (add days or via-point) |
POST |
/api/confirm-route/{job_id} |
Confirm route, begin accommodation loading |
POST |
/api/skip-to-leg-end/{job_id} |
Skip remaining stops and jump to leg end |
POST |
/api/replace-region/{job_id} |
Replace a region with an alternative |
POST |
/api/recompute-regions/{job_id} |
Re-run RegionPlannerAgent from scratch |
POST |
/api/confirm-regions/{job_id} |
Confirm region plan, proceed to stops |
POST |
/api/start-accommodations/{job_id} |
Trigger parallel accommodation fetch |
POST |
/api/select-accommodation/{job_id} |
Select accommodation for one stop |
POST |
/api/confirm-accommodations/{job_id} |
Confirm all accommodation selections |
POST |
/api/start-planning/{job_id} |
Launch full plan generation |
POST |
/api/answer-explore-questions |
Submit answers to explore zone questionnaire |
GET |
/api/progress/{job_id} |
SSE stream of events and debug logs |
GET |
/api/result/{job_id} |
Fetch completed travel plan (JSON) |
POST |
/api/generate-output/{job_id}/{type} |
Generate PDF or PPTX |
GET |
/health |
Health check + active job count |
| Method | Path | Description |
|---|---|---|
POST |
/api/auth/login |
Login, receive JWT access + refresh tokens |
POST |
/api/auth/refresh |
Exchange refresh token for new access token |
POST |
/api/auth/logout |
Invalidate refresh token |
GET |
/api/auth/me |
Get current authenticated user info |
| Method | Path | Description |
|---|---|---|
GET |
/api/admin/users |
List all users (admin only) |
POST |
/api/admin/users |
Create a new user (admin only) |
PATCH |
/api/admin/users/{user_id} |
Update user details or quota (admin only) |
DELETE |
/api/admin/users/{user_id} |
Delete a user (admin only) |
| Method | Path | Description |
|---|---|---|
GET |
/api/travels |
List all saved trips (metadata only) |
POST |
/api/travels |
Save a completed plan |
GET |
/api/travels/{id} |
Load full plan JSON |
PATCH |
/api/travels/{id} |
Update name and/or rating |
DELETE |
/api/travels/{id} |
Delete a saved trip |
POST |
/api/travels/{id}/replan |
Re-run agents against saved route |
POST |
/api/travels/{id}/replace-stop |
Start async stop replacement job |
POST |
/api/travels/{id}/replace-stop-select |
Select replacement stop from options |
Create an account or log in. Admins can manage users and token quotas via the admin panel.
Fill in Start and Destination plus travel dates. Optionally add via-points. Set the max drive hours per day slider. As soon as the required fields are filled, a sticky "Reise jetzt planen" bar appears.
Set adults, add children with ages, and choose travel styles (Abenteuer, Entspannung, Kultur, Romantik, Kulinarik, Roadtrip, Natur, Stadt, Wellness, Sport, Gruppe, Familie, Slow Travel, Party). Add a free-text trip description.
Define your trip legs as Transit (drive from A to B with stops) or Explore (discover a geographic zone). Each leg shows a map with the zone or route segment.
- Accommodation types: Hotel · Apartment · Camping · Hostel · Airbnb
- Must-have amenities: Pool · WiFi · Parking · Kitchen · Breakfast
- Must-do activities as tags, max distance from accommodation
- Min / max nights per stop
- Total budget in CHF with % split sliders (accommodation / food / activities)
- Review summary and submit
After route confirmation, RegionPlannerAgent proposes a region sequence. Review which stops belong to which region, adjust if needed, and confirm before stop selection begins.
Claude proposes 3 stop options per segment, evenly spaced via OSRM geometry. Pick options to build the route iteratively. Features:
- Google Maps with numbered pins and branch lines
- "Neu berechnen" bar for custom re-runs (e.g. "lieber Küste")
- Orange warning badges for drive-limit violations
- Blue "Umweg-Optionen" banner for detour suggestions
- Route-adjust modal when all options exceed the limit
Route map, key stats, Google Maps link, downloads.
Per-stop card: accommodation, activities, restaurants.
Day-by-day breakdown with interactive day maps, driving legs, and highlights.
Itemised: accommodation · fuel · activities · food · total vs. budget.
- Python 3.11+
- Redis running locally (
redis-server)
cd backend
pip install -r requirements.txt
cp .env.example .env # add your API key
python3 -m uvicorn main:app --reload --port 8000cd backend
celery -A tasks worker --loglevel=infoOpen frontend/index.html directly, or serve with any static file server. For local dev without Nginx, change API_BASE in frontend/js/core/api.js to http://localhost:8000/api.
cd backend
python3 -m pytest tests/ -v # all tests
python3 -m pytest tests/test_models.py # Pydantic validation
python3 -m pytest tests/test_endpoints.py # API routes
python3 -m pytest tests/test_agents_mock.py # agents (no API key needed)
python3 -m pytest tests/test_travel_db.py # travel persistence| Variable | Required | Default | Description |
|---|---|---|---|
ANTHROPIC_API_KEY |
Yes | — | Anthropic API key |
JWT_SECRET |
Yes | — | Secret key for JWT signing |
TEST_MODE |
No | true |
true = haiku (cheap dev); false = opus/sonnet |
REDIS_URL |
No | redis://localhost:6379 |
Redis connection string |
GOOGLE_MAPS_API_KEY |
No | — | Google Maps JS SDK + Places API |
ADMIN_USERNAME |
No | admin |
Initial admin username |
ADMIN_PASSWORD |
No | — | Initial admin password |
MAX_DAILY_TOKENS_PER_USER |
No | unbegrenzt | Daily token limit per user |
LOGS_DIR |
No | backend/logs/ |
Log file directory |
BRAVE_SEARCH_API_KEY |
No | — | Brave Search API (optional enrichment) |
| Category | Allocation |
|---|---|
| Accommodation | configurable % (default 60%) |
| Food | configurable % (default 20%) |
| Activities | configurable % (default 20%) |
| Fuel | CHF 12 per driving hour |
DetourAI/
├── backend/
│ ├── main.py # FastAPI app — 25+ endpoints
│ ├── orchestrator.py # TravelPlannerOrchestrator (leg-sequential)
│ ├── agents/
│ │ ├── _client.py # shared Anthropic client + model selector
│ │ ├── route_architect.py # RouteArchitectAgent (opus)
│ │ ├── region_planner.py # RegionPlannerAgent (opus)
│ │ ├── stop_options_finder.py # StopOptionsFinderAgent (sonnet, streaming)
│ │ ├── detour_options_agent.py # DetourOptionsAgent (haiku, fallback)
│ │ ├── explore_zone_agent.py # ExploreZoneAgent (sonnet, two-pass)
│ │ ├── accommodation_researcher.py
│ │ ├── activities_agent.py # + WikipediaEnricher
│ │ ├── restaurants_agent.py
│ │ ├── day_planner.py # DayPlannerAgent (opus)
│ │ ├── travel_guide_agent.py # TravelGuideAgent (sonnet)
│ │ ├── trip_analysis_agent.py # TripAnalysisAgent (sonnet)
│ │ └── output_generator.py # PDF + PPTX
│ ├── models/
│ │ ├── travel_request.py # TravelRequest (leg-based)
│ │ ├── travel_response.py # TravelPlan, TravelStop, DayPlan
│ │ ├── stop_option.py # StopOption, StopOptionsResponse
│ │ ├── accommodation_option.py # AccommodationOption, BudgetState
│ │ ├── trip_leg.py # TripLeg, Transit/Explore modes
│ │ └── via_point.py # ViaPoint, ZoneBBox, ExploreStop
│ ├── routers/
│ │ ├── auth.py # JWT Auth endpoints
│ │ └── admin.py # Admin user management
│ ├── tasks/
│ │ ├── run_planning_job.py # Celery: full orchestration + explore pause
│ │ ├── prefetch_accommodations.py # Celery: parallel acc fetch
│ │ └── replace_stop_job.py # Celery: async stop replacement
│ ├── utils/
│ │ ├── debug_logger.py # DebugLogger + SSE subscriber manager
│ │ ├── maps_helper.py # geocode, OSRM routing, Maps URLs
│ │ ├── retry_helper.py # call_with_retry() + exponential backoff
│ │ ├── json_parser.py # parse_agent_json()
│ │ ├── travel_db.py # SQLite travel persistence
│ │ ├── auth.py # JWT generation & validation
│ │ ├── auth_db.py # SQLite user CRUD + Argon2id
│ │ ├── migrations.py # Versioned DB migration runner
│ │ ├── settings_store.py # Persistent settings storage
│ │ ├── hotel_price_fetcher.py # hotel price fetching
│ │ └── image_fetcher.py # destination image fetching
│ ├── tests/
│ │ ├── conftest.py
│ │ ├── test_models.py # Pydantic validation tests
│ │ ├── test_endpoints.py # API route tests
│ │ ├── test_agents_mock.py # agent tests with mocked Anthropic
│ │ └── test_travel_db.py # travel persistence tests
│ ├── logs/ # daily rotating log files (auto-created)
│ ├── .env.example
│ └── requirements.txt
├── frontend/
│ ├── index.html
│ ├── styles.css
│ └── js/
│ ├── core/ # foundation modules
│ │ ├── state.js # global S object + localStorage helpers
│ │ ├── auth.js # JWT token management + session restore
│ │ ├── router.js # client-side SPA routing
│ │ ├── api.js # all fetch() + SSE calls
│ │ └── i18n.js # translation loader (de/en/hi)
│ ├── maps/ # Google Maps modules
│ │ ├── maps-core.js # map init, markers, autocomplete
│ │ ├── maps-images.js # Place photos + fallback chain
│ │ ├── maps-routes.js # driving route polylines
│ │ └── maps-guide.js # guide tab map + POI markers
│ ├── communication/ # SSE protocol
│ │ ├── sse-client.js # SSE connection lifecycle
│ │ ├── unified-overlay.js # unified spinner overlay (loading + SSE phases)
│ │ └── progress.js # debug log + stops timeline
│ ├── guide/ # travel guide viewer
│ │ ├── guide-core.js # tab switching + entry point
│ │ ├── guide-overview.js # overview tab + trip analysis
│ │ ├── guide-stops.js # stops tab cards
│ │ ├── guide-days.js # day-by-day tab
│ │ ├── guide-map.js # guide map tab
│ │ ├── guide-edit.js # inline stop editing
│ │ └── guide-share.js # PDF/PPTX export + share
│ ├── features/ # planning pipeline + standalone pages
│ │ ├── mode-picker.js # trip mode selection (roadtrip/erkunden/ortsreise)
│ │ ├── form.js # 5-step form + legs builder (roadtrip/erkunden)
│ │ ├── route-builder.js # route builder + explore UI
│ │ ├── accommodation.js # parallel acc loading + grid
│ │ ├── travels.js # saved trips drawer
│ │ ├── settings.js # user settings + quota UI
│ │ ├── sidebar.js # collapsible sidebar nav
│ │ └── feedback.js # user feedback modal
│ └── types.d.ts # generated from OpenAPI
├── docs/
│ └── database.md # DB schema + API reference
├── infra/
│ ├── Dockerfile.backend
│ ├── Dockerfile.frontend
│ └── nginx.conf
├── scripts/
│ └── generate-types.sh # OpenAPI → TypeScript types
├── data/
│ ├── travels.db # SQLite travels (auto-created)
│ └── auth.db # SQLite users & tokens (auto-created)
├── docker-compose.yml
└── outputs/ # generated PDF / PPTX files
Major release bringing a new trip mode, a completely redesigned map layout, and form persistence.
- Ortsreise mode — new single-location trip type with a dedicated one-step form; plan a multi-day stay at one destination without route building
- Three trip modes — mode picker at app start lets users choose Roadtrip, Erkunden, or Ortsreise before entering the form
- Horizontal collapsible map — guide map redesigned from a fixed left panel (45% width) to a full-width horizontal strip above the content; collapse/expand toggle with animated transition; sticky on mobile
- Hotel & activity pins on main map — hotel (🏨) and activity emoji markers loaded async alongside numbered stop markers; coordinates resolved via session-cached Google Places API
- Marker filter pills — three toggle buttons (Stopps / Hotels / Aktivitäten) independently control which marker types are visible
- Dim/restore across entity types — drill-down into day or stop dims hotel/activity markers for non-focused stops as well as stop markers
- Form persistence — full form state (all 5 steps + legs) saved to localStorage; survives page refresh; cleared on successful submission
- Unified progress overlay —
loading.jsandsse-overlay.jsmerged intounified-overlay.js; single overlay handles both app loading and SSE planning phases - Header refresh — flat design with version badge, subtle animations
- 327 tests passing
Complete end-to-end application of a project-wide code documentation standard across all 66 source files.
- English-first comments — all code comments, docstrings, and internal documentation now in English; user-facing strings remain in the configured language
- Python module docstrings — every
.pyfile (except__init__.py) has a one-line module docstring as the first statement - Python class & function docstrings — all non-Pydantic classes and functions with 3+ parameters have docstrings explaining their purpose
- JS file header contracts — every
.jsfile starts with a three-line dependency contract (// Description / Reads: / Provides:) making module dependencies explicit - JS function JSDoc — all exported/global functions listed in
Provides:have/** one-line description */blocks - Section dividers —
# ---(Python) and// ---(JS) dividers separate logical sections in every file - Zero functional changes — purely documentation; all 319 tests pass unchanged
- Multi-language support — full de/en/hi i18n across frontend and backend; language switcher in UI
- RegionPlanner country names — region names always include country (e.g. "Peloponnes, Griechenland") to prevent geocoding ambiguity
- Frontend JS modularisation — 27 JS files reorganised from flat directory into 5 specialised worker folders (
core/,maps/,communication/,guide/,features/), each with its ownCLAUDE.md - Truncated JSON repair —
json_parser.pyautomatically repairs truncated Claude responses to prevent job failures - Explore mode start-point fix — user's departure point correctly preserved through explore mode planning
- SSE message keys — progress events carry language-independent
message_keyfields for i18n-safe frontend rendering
- Stop replacement — swap any stop in a saved trip; async Celery job re-runs all research for the new destination
- Add / remove / reorder stops — full CRUD on the stop list of a saved trip
- Update nights — adjust the night count per stop and trigger day plan recalculation
- Route edit locking — optimistic locking prevents concurrent edits from corrupting trip state
- Pre-flight token estimation — estimates job cost before starting; blocks if user quota would be exceeded
- Token tracking per agent — token usage captured and persisted per-job
- User quota enforcement — daily token limits with inline error messages on quota exhaustion
- Mid-job quota handling — graceful error display if quota is exceeded during an active job
- JWT-based authentication — login/register with Argon2id password hashing
- Refresh tokens — silent session renewal without re-login
- Admin panel — full user management UI (create, edit, delete users)
- Per-user token quotas — configurable daily limits, visible in user settings
- Client-side SPA routing —
router.jshandles auth-guarded page transitions - Settings UI —
settings.jsexposes quota usage and user preferences
- RegionPlannerAgent — autonomous multi-region planning after route confirmation; user reviews and confirms before stop selection
- Region UI — interactive region plan with replace, recalculate, and confirm actions
- Interactive day maps — route polylines with accommodation, restaurant, and activity POI markers per day
- Replace stop — swap any stop in a saved trip; async Celery job re-runs all research for the new destination
- File-based logging — daily rotating log files in
backend/logs/with 30-day retention; separate files per agent - Frontend error reporting —
window.onerrorand unhandled rejections auto-reported to backend log
Major architectural upgrade: trips are now composed of legs instead of flat segment sequences.
- Leg-based trip architecture — TravelRequest refactored from flat via-points to typed
TripLegobjects (Transit or Explore mode) - Explore mode — new leg type that lets users define a geographic zone and discover stops via a guided questionnaire
- ExploreZoneAgent — new two-pass agent: generates questions → processes answers → returns categorised stops (anker/landschaft/geheimtipp)
- StopOptionsFinder explore branch — new option types for explore legs: anchor points, scenic spots, hidden gems
- Legs Builder UI — Step 3 redesigned with Transit/Explore leg cards and map zone selection
- Explore UI in Route Builder — zone guidance overlay, circular route display, explore questionnaire flow
- Orchestrator refactored — leg-sequential planning with explore-phase pause/resume logic
- POST /api/answer-explore-questions — new endpoint for explore questionnaire answers
- All tests updated for legs-based architecture
Complete frontend redesign and map provider migration.
- Google Maps JS SDK migration — replaced Leaflet & Unsplash with Google Maps + Places API
- Google Maps Places API — real photos via Nearby Search, photo strips with lightbox
- Travel-Forward rebrand — sky-blue + adventure-orange design system
- Lucide SVG icons — all emojis and text icons replaced with consistent SVGs
- Full accessibility pass — focus rings, aria labels, sr-only labels, keyboard navigation, screen-reader compatibility
- Collapsible stops + sidebar navigation — improved travel guide UX with calendar tab
- Full-width layout — gallery UX with lightbox navigation
- Step indicators as click navigation — jump to completed steps
- Auto-balancing budget sliders — automatically maintain 100% sum
- Mobile improvements —
100dvhviewport, visible step labels on small screens - Inline field validation — replaced
alert()with inline error messages - Wait-time hint + cancel button — user feedback during long planning phases
- Advanced settings — proximity sliders hidden under expandable section
- Performance — parallelised StopOptionsFinder enrichment, reduced timeouts, eliminated geocoding duplication
- 529 Overloaded error handling — exponential backoff retry for API overload
- Travel guide agent — narrative storytelling guide with hourly day plans per stop
- Trip analysis agent — post-planning requirement evaluation with tags and keyword highlighting
- Replan saved trips — re-run agents against saved route and accommodations
- Accommodation system overhaul — free-text wishes, all options included in final plan
- Rename + star rating — inline rename and 0–5 star widget for saved trips
- SSE via Redis relay — Celery worker events reliably forwarded to FastAPI
- Database documentation — full schema reference in
docs/database.md
- Live progress overlay — semi-transparent overlay with spinner log during all three wait phases; each step flips to a green checkmark on completion
- "Direkt weiterfahren" — skip a stop and redistribute freed nights to the next destination
- Proximity filter in GUI — two sliders to control minimum distance from start/target
- Geo-bounded detours — DetourOptionsAgent uses explicit bounding box (±1.5°) to keep suggestions in range
- Retry optimisation — skip retry pass when 0 valid stops, go directly to DetourOptionsAgent
- Correct map markers — "S" marker always shows the last confirmed stop
- SQLite travel history — "Meine Reisen" with save, load, and delete
- DetourOptionsAgent — automatic fallback when StopOptionsFinder returns 0 valid options on short segments
- Rundreise mode — round-trip detection with deliberate detour options (left, right, adventure)
- Interactive map markers — click-to-select, hover tooltips, number matching
- Minimum stop distance validation — proximity filter for stop placement
- Rundreise threshold — minimum 200 km to prevent false positives
- Style-based accommodation search — 3 options based on travel style instead of hardcoded types
- UTM VM Docker host delegation — Docker deployment from virtual machines
- Booking.com deeplinks — direct booking links and "Geheimtipp" option
- 4x speed improvement — parallelised route option display
- Security hardening — XSS prevention, job enumeration protection, port restrictions
- Docker deploy pipeline — fixed OUTPUTS_DIR path resolution
- 6-step form → Route · Travellers · Activities · Accommodation · Budget · Summary
- Budget split sliders — configurable % with live CHF preview and 100% validation
- Geometry-aware etappe planning — OSRM-measured distances for even stop distribution
- Drive-limit enforcement — OSRM-verified times with orange warning badges
- Route-adjust modal — add days or insert via-points when all options exceed limits
- Sticky quick-submit bar — "Reise jetzt planen" visible from any form step
- Leaflet map in route builder — start/target pins, numbered option pins, dashed branch lines
- Interactive guide map — clickable stop pins navigating to detail cards
- Agent-supplied coordinates — WGS84 lat/lon fallback when geocoding fails
- "Neu berechnen" bar — free-text instruction to re-run the agent
- OSRM-verified drive times — real road distances replace AI estimates
- Unsplash image galleries with lightbox support
- Full 5-step form with travel style selection
- 6 AI agents with structured JSON communication
- Server-Sent Events for real-time progress streaming
- PDF and PPTX export
- Swiss-first: all output in German, all prices in CHF
MIT









