# Low Level Design: Travel Itinerary Service

Source: https://www.techinterview.org/post/3233471618/lld-travel-itinerary/
Updated: 2026-07-13 · techinterview.org

## What Is a Travel Itinerary Service?

Users plan and manage multi-component trips: flights, hotels, car rentals, and activities stitched together in a timeline. The low-level design must handle heterogeneous booking types, time-zone-aware scheduling, conflict detection, and collaborative sharing between travelers.

## Data Model


```
-- Core tables (SQL pseudocode)

CREATE TABLE itineraries (
  itinerary_id    BIGINT PRIMARY KEY,
  owner_user_id   BIGINT,
  title           VARCHAR(255),
  start_date      DATE,
  end_date        DATE,
  status          VARCHAR(32),  -- 'DRAFT', 'CONFIRMED', 'COMPLETED', 'CANCELLED'
  currency        CHAR(3),
  created_at      TIMESTAMP,
  updated_at      TIMESTAMP
);

CREATE TABLE itinerary_items (
  item_id         BIGINT PRIMARY KEY,
  itinerary_id    BIGINT REFERENCES itineraries(itinerary_id),
  item_type       VARCHAR(32),  -- 'FLIGHT', 'HOTEL', 'CAR', 'ACTIVITY'
  external_ref_id VARCHAR(128), -- booking ID from external service
  title           VARCHAR(255),
  start_datetime  TIMESTAMP WITH TIME ZONE,
  end_datetime    TIMESTAMP WITH TIME ZONE,
  location        VARCHAR(255),
  cost            DECIMAL(10,2),
  currency        CHAR(3),
  status          VARCHAR(32),  -- 'PENDING', 'CONFIRMED', 'CANCELLED'
  notes           TEXT,
  sort_order      INT
);

CREATE TABLE itinerary_collaborators (
  itinerary_id    BIGINT REFERENCES itineraries(itinerary_id),
  user_id         BIGINT,
  role            VARCHAR(16),  -- 'VIEWER', 'EDITOR', 'OWNER'
  invited_at      TIMESTAMP,
  accepted_at     TIMESTAMP,
  PRIMARY KEY (itinerary_id, user_id)
);

CREATE TABLE itinerary_documents (
  doc_id          BIGINT PRIMARY KEY,
  itinerary_id    BIGINT REFERENCES itineraries(itinerary_id),
  doc_type        VARCHAR(32),  -- 'TICKET', 'VOUCHER', 'PASSPORT'
  storage_url     VARCHAR(512),
  uploaded_at     TIMESTAMP
);
```


## Core Algorithm: Conflict Detection

When a user adds or moves an itinerary item, the service checks for time overlaps against existing confirmed items. The overlap condition for two intervals A and B is: `A.start < B.end AND A.end > B.start`. All datetime comparisons are performed in UTC after normalizing from local time zones using the item location's IANA timezone.

  - On item insert or update, load all confirmed items for the itinerary.

  - Convert all timestamps to UTC.

  - Check the new item against each existing item for overlap.

  - Return a list of conflicts (not a hard block, since layovers and quick transfers are valid in some cases); flag them as warnings in the UI.

## Aggregation Workflow: Building the Timeline

The itinerary timeline is assembled by:

  - Fetching all `itinerary_items` for the given `itinerary_id`, ordered by `start_datetime ASC, sort_order ASC`.

  - Grouping items by local calendar date at the destination timezone to produce a day-by-day view.

  - Computing gaps between consecutive items and surfacing them as free time slots in the UI.

  - Aggregating total cost across all items grouped by currency, with an optional FX conversion to the itinerary base currency using a daily exchange rate lookup.

## Failure Handling

  - For partial booking failures, if a flight books but the hotel call fails, the itinerary item for the hotel is left in `PENDING` status and a retry job is enqueued. The user is notified of the partial failure and can manually retry or substitute.

  - For cancellation propagation, cancelling a flight that is the only way to reach a hotel destination triggers a warning that downstream hotel and activity items may need to be cancelled too. The system does not auto-cancel dependents; it surfaces a checklist.

  - For collaborative edit conflicts, two editors moving the same item simultaneously use optimistic locking via an `updated_at` version check. The second writer receives a conflict error and must reload before saving.

  - For time-zone edge cases, all stored timestamps are UTC. Display conversion happens client-side using the item location timezone, preventing DST ambiguity in stored data.

## Scalability Considerations

  - The read-heavy profile matters: itinerary reads (viewing the timeline) vastly outnumber writes. Cache the assembled timeline in Redis, keyed by `itinerary_id:version`, and invalidate on any item write.

  - For document storage, tickets and vouchers are stored in object storage (S3-compatible) with signed URLs; the database holds only the metadata reference.

  - For event-driven updates, external booking status changes (flight delay, hotel confirmation) arrive as webhook events and are processed by a consumer that updates the relevant `itinerary_items` row and pushes a real-time notification via WebSocket or push notification.

  - For sharing at scale, public share links generate a read-only token stored alongside the itinerary. Shared views are served from a CDN-cached snapshot refreshed on write, eliminating database load for viral itinerary shares.

  - For search, users search their past and upcoming itineraries by destination or date range. Index `itineraries` in Elasticsearch with denormalized location and date fields to support fast full-text and range queries without scanning the main database.

See also: [Airbnb Interview Guide 2026: Search Systems, Trust and Safety, and Full-Stack Engineering](https://www.techinterview.org/post/3233460279/airbnb-interview-guide-2026-search-systems-trust-and-safety-and-full-stack-engineering/)

See also: [Netflix Interview Guide 2026: Streaming Architecture, Recommendation Systems, and Engineering Excellence](https://www.techinterview.org/post/3233460274/netflix-interview-guide-2026-streaming-architecture-recommendation-systems-and-engineering-excellence/)

See also: [Scale AI Interview Guide 2026: Data Infrastructure, RLHF Pipelines, and ML Engineering](https://www.techinterview.org/post/3233460275/scale-ai-interview-guide-2026-data-infrastructure-rlhf-pipelines-and-ml-engineering/)
