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
| 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 |