Building a full-stack travel platform where content discovery meets AI-powered trip planning, a zero-to-one product with a three-layer architecture.
Travel planning is fundamentally fragmented. A user opening Google to plan a two-week trip to Southeast Asia faces dozens of tabs: itinerary blogs, budget hostel lists, YouTube vlogs, transport forums, and cultural guides, none of which talk to each other.
Existing all-in-one platforms (Tripadvisor, Lonely Planet) surface static content. AI chat tools (ChatGPT) have broad knowledge but no real-time web access and no domain specialization. No product occupies the intersection of curated editorial content and live, conversational AI planning.
The opportunity I was designing for:
The core insight: travelers don't lack information. They lack a trusted companion who speaks their specific journey (budget, culture, and route all at once) in real time.
I defined three distinct user segments with different jobs to be done, each shaping product priorities differently.
Researches every dollar. Needs quick hostel comparisons, overland routes, and budget breakdowns often from mobile while already travelling.
"Give me three hostels under $15 in Chiang Mai sorted by proximity to night bazaar."
Planning 2–4 weeks in advance. Reads blog itineraries but wants to adapt them: remove days, swap destinations, or add experiences without rebuilding from scratch.
"Build me a 10-day Japan route starting in Tokyo but I want to skip Osaka."
Wants to go beyond tourist trails. Seeks tipping customs, food etiquette, hidden night markets, and context that no static article provides.
"What are the cultural norms I should know before visiting Vietnam's temples?"
Rather than a monolithic app, I designed Travelerstab as three distinct services, each owning a specific concern. This separation of concerns drove every technical and product decision downstream.
The three-service split was a deliberate product choice: the AI service can be swapped or upgraded independently of the content layer, and the CMS allows non-technical editors to update itineraries without touching any code.
The AI layer is where most product decisions centered. I designed a multi-agent architecture that balances response speed, specialization depth, and resource efficiency.
The supervisor agent. Handles casual conversation and small queries instantly, with no tool calls and no latency overhead. Routes complex queries to the right specialist based on intent classification.
Specializes in live hostel, hotel, and Airbnb searches via DuckDuckGo. Compares budgets, surfaces location advantages, and structures results as readable comparison tables.
Transport logistics and day-by-day itinerary generation. Sources live flight, bus, and train options, then structures them into temporal, step-by-step travel plans.
Customs, authentic food recommendations, hidden gems, and local etiquette. Combines web search results with cultural context that generic LLMs lack specificity on.
A single model instance (Gemini 2.0 Flash or Gemma 4B locally) serves all four agents. This was a hard resource efficiency constraint: one LLM in VRAM, not four.
Responses are streamed token-by-token via Server-Sent Events from FastAPI to the Next.js frontend. Users see the AI "typing" in real-time, masking backend latency perceptually.
The most tempting path was building four capable agents in parallel. Instead, I prioritized Trava, the router, first. A brilliant specialist agent is worthless if the product routes users to the wrong one. The router's intent classification is the product experience. Getting this right early saved weeks of context-engineering downstream.
Multi-agent searches using DuckDuckGo can take 15–30 seconds end-to-end. Without streaming, a blank screen for 30 seconds would feel broken. Server-Sent Events with progressive Markdown rendering mean users see content arriving within 1–2 seconds of submitting a query. I made SSE a hard architectural requirement before writing a single API route.
Supporting LM Studio with Gemma 4B was debated as a "nice-to-have." I pushed it to a hard requirement. Two reasons: (1) it validated the agent service's cost efficiency, since the product could run completely free, removing a financial barrier to personal use and demos; (2) it forced an OpenAI-compatible interface that made the cloud/local model swap a one-line config change, improving architecture robustness.
Chat UX has one critical, easy-to-miss edge case: if a user scrolls up mid-stream to re-read something, auto-scroll snapping them back to the bottom is infuriating. I implemented scroll-intent detection: the UI only auto-scrolls if the user is already near the bottom. Tiny feature, major trust impact. The kind of detail users never notice when it works, but immediately abandon the product over when it doesn't.
The Strapi CMS wasn't just about editorial convenience. By structuring affiliate products as a first-class content type inside the CMS (with tracking link fields built in), I created a monetization loop that any non-technical operator can manage. The "Recommendations" page is the affiliate commerce layer, and Strapi makes it editable without deploying code. This separation keeps the revenue engine independent of engineering velocity.
The hardest decisions weren't technical, they were about what not to build. User auth, booking integrations, and maps are all powerful expansions. Keeping them on the roadmap but out of v1 was what made v1 shippable.
Every feature in v1 was evaluated against one question: does this directly serve the core job-to-be-done of one of our three user segments? Here's how the feature set maps to user needs.
Each technology selection had a product rationale, not just an engineering one. This is how I framed the stack decisions as a PM.
| Layer | Technology | PM Rationale |
|---|---|---|
| Frontend | Next.js 14 App Router | SSR for SEO on itinerary pages; streaming support for AI chat, both needs in one framework. |
| Styling | Tailwind CSS + Framer Motion | Dark mode + neon theme is the brand. Framer Motion enables the micro-interactions that make the product feel premium, not prototype-grade. |
| CMS | Strapi 4 | Headless: editorial team can update itineraries without code deploys. Affiliate links are structured data, not hard-coded strings. |
| AI Framework | Agno (Phidata) | Python-native multi-agent orchestration with tool integration. Agno's team abstraction maps directly onto the Router + Specialist design pattern. |
| AI API | FastAPI + Uvicorn | SSE streaming support is first-class in FastAPI. Critical for the real-time UX requirement. |
| LLM (cloud) | Gemini 2.0 Flash | Speed and cost. Flash-tier models handle the conversational + search synthesis tasks well within latency budgets users tolerate. |
| LLM (local) | Gemma 4B via LM Studio | Full offline capability. Cost-free. Forces OpenAI-compatible API contract, making cloud/local swapping a config change. |
| Search | DuckDuckGo Tool | Live web access without API key overhead. Used inside specialist agents to surface real-time hostel, transport, and cultural data that no static LLM has. |
| Database | SQLite (dev) / PostgreSQL (prod) | Zero-config dev setup. PostgreSQL for production durability and Strapi's recommended scale path. |
The v1 architecture was deliberately designed to accommodate the next four features without a rewrite. Here's the sequenced roadmap and why each phase was deferred.
Deferred from v1 because it adds auth infrastructure cost without changing the core value prop. Once SSO is live, users can save AI-generated plans to an account, converting one-session visitors into retained users.
The agent service already has a MongoDB hook in the architecture, intentionally dormant in v1. Activating it lets Trava remember users' past trips across sessions, moving from a stateless tool to a contextual travel companion.
The Route and Accommodation agents currently surface options. The next step is allowing users to complete bookings without leaving the chat. This is the highest-revenue opportunity but requires API partnership agreements.
When the Route Agent generates a day-by-day plan, rendering a Mapbox or Google Maps component inline in the response transforms a text output into a spatial, navigable experience. Deferred because it requires frontend Markdown component extension, not urgent for v1 validation.
Travelerstab wasn't just a technical project, it was a product strategy exercise. Every architectural decision had a PM reason: the three-layer split enables independent scaling, the multi-agent design enables domain depth, the streaming UX enables perceived performance. The hardest skill in a 0→1 build isn't building broadly, it's knowing exactly where to draw the line, and being able to defend why everything on the other side of it becomes a roadmap item.
Scope discipline is the only thing that makes ambitious architecture shippable.