Project record

03 / 03

Explainable travel recommendation engine

Viazio

It picks when and where to travel by weighing holidays, weather, cost, and distance, and shows why each destination landed in that position instead of handing over a single score. When an upstream source goes down, the ranking stays standing and says what was missing.

Viazio compares travel windows and destinations through weather, cost, distance, and calendars. Its response separates score, coverage, and confidence so it remains useful when a provider fails without presenting missing data as observed data.

Period
03.2026 · 07.2026
My contribution
Recommendation-engine architecture, external integrations, persistence, Spring Boot API, and React frontend.
Technology
Java 21 · Spring Boot · React 19 · PostgreSQL · Resilience4j
Status
Published version
Horizontal Viazio logo in gold and white on a navy blue grid
Viazio identity for the product that compares destinations and exposes how each ranking is composed.

RING

Ranking destinations with incomplete data

Weather, exchange rates, holidays, economic indicators, and editorial content have different lifetimes and failure modes. Waiting for every source makes ranking slow; replacing missing data with zero punishes a destination for a provider failure.

SECTOR

How the ranking degrades

  1. Score and coverage remain separate

    Four strategies calculate weather, cost, distance, and festivities. When a criterion is missing, available weights are normalized and coverage lowers final confidence without inventing a score.

  2. Failures stay isolated by provider

    Retries, circuit breakers, and bulkheads keep independent state. A Wikipedia outage removes editorial content without opening the weather, holiday, or World Bank circuits.

  3. PostgreSQL before the network

    Reads use persisted data with fetched_at, stale_at, and expires_at. A miss gets at most two seconds of synchronous work; after that, the response degrades and a refresh enters the queue.

  4. Bounded concurrency per candidate

    Candidates are evaluated on virtual threads, while the refresh queue uses priorities and ShedLock. One candidate's failure does not stop the remaining ranking.

MARK

Executable evidence

  • 250 backend tests and 17 frontend unit tests
  • Five remote providers with separate cache, protection, and failure behavior
  • A persisted refresh queue for missing, expired, or low-confidence data
  • A public application with no account requirement, a versioned API, and an open repository

SHEET