Skip to content

TripMaker — General Requirements

Version 2.0 March 2026

Supersedes: requirement-specs.md (v1.0, November 2025)


1. Executive Summary

TripMaker is a travel itinerary planning and quotation module within TQPro. It enables travel agents to build multi-destination trip packages for individual and small-group travelers, integrating real-time supplier search (flights, hotels, activities), AI-assisted planning, cost management with configurable margins, and professional PDF quotation generation.

Key capabilities:

  • Multi-destination itinerary planning with multiple option scenarios
  • Supplier-agnostic integration: Google Flights via RapidAPI (flights), GoGlobal (hotels), Tiqets (activities)
  • AI-powered travel brief generation (Claude API) with actionable area/activity links
  • Per-component cost overrides with margin management
  • Client-facing PDF quotation (no internal costs exposed)
  • Hub-and-spoke navigation: Dashboard → Project Hub → sub-pages

2. Stakeholders and Actors

Actor Description
Travel Agent Primary user. Creates projects, builds itineraries, manages costs, generates quotations
Administrator Manages system configuration, user access, and supplier settings
System Automated functions: AI brief generation, cost recalculation, PDF rendering, supplier API calls

3. Functional Requirements

FR-PM: Project Management

ID Requirement
FR-PM-001 Create trip project with traveler details (name, age range, gender), destinations, dates, flexibility, holiday type, budget tier, departure city
FR-PM-002 Default budget tier to "mid-range" and departure city to "Dubai" when not specified
FR-PM-003 List projects filtered by agent, status, date range; sorted by last modified descending; paginated
FR-PM-004 Update project master data (all fields editable)
FR-PM-005 Delete project with cascading deletion of all child entities
FR-PM-006 Load expanded project view with itineraries and per-itinerary component counts
FR-PM-007 Project statuses: DRAFT, ACTIVE, QUOTED, CLOSED

FR-IT: Itinerary Management

ID Requirement
FR-IT-001 Create itinerary within a project with a descriptive name
FR-IT-002 Support multiple itineraries per project (option scenarios)
FR-IT-003 List itineraries for a project with component counts
FR-IT-004 Update itinerary name and status
FR-IT-005 Delete itinerary with cascading deletion of components
FR-IT-006 Itinerary statuses: DRAFT, ACTIVE, COMPLETED

FR-FL: Flight Management

ID Requirement
FR-FL-001 Search flights via Google Flights (RapidAPI) with origin, destination, date, cabin class, passenger count
FR-FL-002 Support flight types: OUTBOUND, RETURN, INTERNAL
FR-FL-003 Add flight to itinerary with full details: route, times, layovers, airline, cabin, cost per person
FR-FL-004 Capture airport transport details (type: PRIVATE_TRANSFER, SHARED_TRANSFER, TAXI, PUBLIC, NONE; cost; notes)
FR-FL-005 Store supplier-agnostic offer reference (supplierOfferId, supplierCode)
FR-FL-006 List flights for an itinerary sorted by departure datetime
FR-FL-007 Remove flight from itinerary

FR-HT: Hotel/Accommodation Management

ID Requirement
FR-HT-001 Search hotels via GoGlobal integration with city code, dates, adults, room quantity, currency, nationality
FR-HT-002 Paginated search results (1-indexed page numbers)
FR-HT-003 Group search results by hotel name showing hotel card with thumbnail, stars, city, "from" price, room count
FR-HT-004 Room selection modal per hotel group showing room type, board type, beds, cancellation policy, price
FR-HT-005 City code resolution with best-match algorithm: exact → starts-with → first result
FR-HT-006 Add accommodation to itinerary with property details, dates, room type, cost
FR-HT-007 Star rating display (1–5 stars from supplier category field)
FR-HT-008 List accommodations sorted by check-in date
FR-HT-009 Remove accommodation from itinerary

FR-AC: Activity Management

ID Requirement
FR-AC-001 Search activities via Tiqets integration by city name with pagination
FR-AC-002 City resolution: Tiqets city ID lookup by exact then partial match on city name
FR-AC-003 Add activity to itinerary with date, time period, name, description, duration, transport/guide flags
FR-AC-004 Support manual (custom) activity entry alongside Tiqets search results
FR-AC-005 Activity sources: TIQETS, MANUAL
FR-AC-006 Time periods: MORNING, AFTERNOON, EVENING, FULL_DAY
FR-AC-007 Calendar view (7-column grid with time-slot rows) and list view toggle
FR-AC-008 Keyword extraction from AI brief activity links (strip action prefixes/suffixes for search pre-fill)
FR-AC-009 Update and delete activities; manage display order

FR-EX: Exclusion Management

ID Requirement
FR-EX-001 Add exclusion text items to an itinerary with auto-incrementing display order
FR-EX-002 Common exclusion suggestions for quick-add (travel insurance, personal expenses, tips, etc.)
FR-EX-003 Update exclusion text
FR-EX-004 Delete exclusion
FR-EX-005 Reorder exclusions (move up/down)
FR-EX-006 Display exclusions as light-pink pills in project hub KPI cards

FR-CS: Cost Management

ID Requirement
FR-CS-001 Generate itemized cost breakdown per itinerary: flights, accommodations, activities
FR-CS-002 Default margin: 10%
FR-CS-003 Per-component margin percentage: finalPrice = baseCost × (1 + margin/100)
FR-CS-004 Manual price override with back-calculated effective margin and adjustment reason
FR-CS-005 Global margin: apply uniform margin percentage across all components of an itinerary
FR-CS-006 Visual indicator for manually adjusted components
FR-CS-007 Cost override persistence keyed by component type + component ID

FR-PDF: PDF Quotation

ID Requirement
FR-PDF-001 Generate PDF from HTML template using OpenHTMLtoPDF (openhtmltopdf-pdfbox)
FR-PDF-002 Templates loaded from TLINQ_HOME/templates/tripmaker/ first, classpath fallback if not found
FR-PDF-003 Client-facing content only: no base costs, margins, or internal pricing in output
FR-PDF-004 Flights table: Route, Departure, Arrival, Airline, Flight #, Cabin (no cost column)
FR-PDF-005 Accommodations table: Hotel, Location, Check-in, Check-out, Nights, Room Type (no cost column)
FR-PDF-006 Activities table: Date (DD-MMM format), Description (name + description) — 2-column simplified layout
FR-PDF-007 Other services table: Date (DD-MMM format), Description (category + description) — 2-column layout
FR-PDF-008 Trip schedule: chronological timeline of all components (flights, check-in/check-out, activities, other services) sorted by date/time
FR-PDF-009 Exclusions as bullet list
FR-PDF-010 Cost summary rows: component type + description only (no amounts); enriched flight descriptions with airline code and date
FR-PDF-011 Title: "Itinerary Summary" with destination, traveler details, dates, holiday type
FR-PDF-012 Store generated PDF as BYTEA in database with metadata (file name, size, status, download/email counters)
FR-PDF-013 Download PDF (base64 response, increment download counter)
FR-PDF-014 Email PDF to recipient address via MailUtil

FR-BRO: PDF Brochure

ID Requirement
FR-BRO-001 Generate brochure PDF from AI brief data + trip schedule (no pricing)
FR-BRO-002 Template: pdf-brochure-template.html loaded via same externalization mechanism as quotation
FR-BRO-003 Content: cover header, timing badge, narrative, recommended areas, sights/activities, trip schedule, practical info
FR-BRO-004 Strictly no prices, margins, or cost data in the brochure output
FR-BRO-005 Trip schedule uses same chronological rendering as quotation PDF
FR-BRO-006 XHTML-compliant output (numeric character references only, no HTML5-only named entities)

FR-AI: AI Brief

ID Requirement
FR-AI-001 Generate AI travel brief via Claude API through AiOutlineFacade
FR-AI-002 Brief content: headline, timing score (1–5), narrative, recommended areas, sights & activities, practical info
FR-AI-003 7-day cache with SHA-256 key (includes departure city, traveler nationalities/residences)
FR-AI-004 Area cards link to hotel search page with area parameter pre-filling city search
FR-AI-005 Activity/sight cards link to activity search page with extracted keyword (extractSearchKeyword)
FR-AI-006 Re-render AI brief links when agent switches itinerary (updates itineraryId in URLs)
FR-AI-007 Feedback collection (thumbs up/down) via /ai/outline/feedback endpoint
FR-AI-008 Traveler nationality and residence codes propagated to AI prompt for nationality-specific visa requirements

FR-DB: Dashboard

ID Requirement
FR-DB-001 KPI cards: Total Projects, Active, Quoted, Draft — counts by status
FR-DB-002 Project cards with traveler last names title, destination badges, dates, status
FR-DB-003 Client-side filtering by search text and destination
FR-DB-004 Create/Edit project modal with traveler detail rows, destination autocomplete chips
FR-DB-005 Project hub: enriched KPI section cards showing item lists (flight routes, hotel names with city, activity dates+names, exclusion pills)
FR-DB-006 Manage button in each section card header linking to the sub-page

4. Non-Functional Requirements

Performance

ID Requirement
NFR-001 API search requests return results within 5 seconds
NFR-002 Cost recalculations complete within 1 second
NFR-003 PDF generation completes within 10 seconds
NFR-004 Support 50 concurrent agents

Security

ID Requirement
NFR-005 HTTPS/TLS for all data transmission
NFR-006 Authentication required for all endpoints (agent or admin role)
NFR-007 Agents access only their own projects
NFR-008 No guest access to any TripMaker endpoint
NFR-009 API credentials never exposed to client-side code

Browser Support

ID Requirement
NFR-010 Chrome, Firefox, Safari, Edge (latest versions)
NFR-011 Responsive layout for desktop and tablet

5. Data Model

5.1 Entity Summary

Entity Class ID Field DB Table Key Fields
CTripProject entity.tripmaker.CTripProject projectId nts.trip_project agentId, travelerCount, travelerDetails (JSON), destinations (JSON), dates, holidayType, budgetTier, departureCity, status
CItinerary entity.tripmaker.CItinerary itineraryId nts.trip_itinerary projectId (FK cascade), itineraryName, status
CFlightOption entity.tripmaker.CFlightOption flightOptionId nts.flight_option itineraryId (FK), flightType, origin/dest airports, times, layovers (JSON), airline, cabin, baseCostPerPerson, airportTransport (JSON), supplierOfferId
CAccommodationOption entity.tripmaker.CAccommodationOption accommodationId nts.accommodation_option itineraryId (FK), city, propertyName, starRating, dates, roomType, mealPlan, amenities (JSON), baseCostTotal, supplierOfferId
CActivity entity.tripmaker.CActivity activityId nts.activity itineraryId (FK), date, timePeriod, name, description, duration, transport/guide flags, baseCostTotal, source, supplierOfferId
CExclusion entity.tripmaker.CExclusion exclusionId nts.exclusion itineraryId (FK cascade), exclusionText, displayOrder
CCostOverride entity.tripmaker.CCostOverride overrideId nts.cost_override componentType, componentId, originalBaseCost, marginPercentage, finalPrice, manuallyAdjusted, adjustmentReason
CGeneratedPdf entity.tripmaker.CGeneratedPdf pdfId nts.generated_pdf projectId (FK cascade), itineraryId, fileName, pdfData (BYTEA), fileSize, status, downloadCount, emailsSent

5.2 Entity Relationships

CTripProject (1)
    ├── CItinerary (*)         [projectId FK, cascade delete]
    │       ├── CFlightOption (*)        [itineraryId FK]
    │       ├── CAccommodationOption (*) [itineraryId FK]
    │       ├── CActivity (*)            [itineraryId FK]
    │       ├── CExclusion (*)           [itineraryId FK, cascade delete]
    │       └── CCostOverride (*)        [componentType + componentId]
    └── CGeneratedPdf (*)      [projectId FK, cascade delete]
                                [itineraryId FK]

5.3 JSON Fields

Field Entity Content
travelerDetails CTripProject [{name, age (CHILD/TEEN/ADULT/SENIOR), gender}]
destinations CTripProject ["Dubai", "Bali", ...]
layovers CFlightOption [{airport, durationMinutes}]
airportTransport CFlightOption {type, cost, notes}
amenities CAccommodationOption ["WIFI", "POOL", "SPA", ...]

6. Integration Points

Integration Supplier Purpose Plugin/Facade
Flights Google Flights (RapidAPI) Flight search and return flight selection tqgflights module, FlightSearchFacade
Hotels GoGlobal Hotel search and booking HotelSearchFacade via GoGlobal plugin
Activities Tiqets Experience/activity catalog TiqetsFacade / TiqetsCatalogFacade
AI Brief Claude API Travel outline generation AiOutlineFacade
PDF OpenHTMLtoPDF HTML-to-PDF rendering openhtmltopdf-pdfbox:1.1.31
Email SMTP PDF quotation distribution MailUtil

Supplier Configuration

Supplier routing is governed by the nts.supplier_config table:

Component Current Supplier
Flights Google Flights (RapidAPI)
Hotels GoGlobal
Activities Tiqets

All entities use supplier-agnostic fields (supplierOfferId, supplierCode) replacing the legacy amadeusOfferId.


7. Glossary

Term Definition
Trip Project Top-level container for all itinerary planning for a single trip inquiry
Itinerary A complete travel plan option. Multiple itineraries exist within a project for comparison
Base Cost Cost from supplier API before margin
Sales Margin Percentage added to base cost: Final = Base × (1 + Margin%)
Exclusion Item not included in the package price
AI Brief AI-generated travel overview with area recommendations and activity suggestions
KPI Card Dashboard metric card showing count and enriched item details
Supplier-Agnostic Design allowing swap of backend suppliers without frontend changes

Document Control

Version Date Description
1.0 November 2025 Initial requirements (as requirement-specs.md)
2.0 March 2026 Complete rewrite: TQ-62 changes, supplier-agnostic model, AI brief, GoGlobal/Tiqets integration