Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/viet2811/uk-travel-recommendation/llms.txt

Use this file to discover all available pages before exploring further.

By default, UK Travel Recommendation draws from the entire national attractions database when building your personalised feed. Geo-area filtering lets you narrow that pool to a specific part of the UK — useful when you are planning a weekend in Cornwall, researching a trip to Scotland, or simply want to discover hidden gems close to home. The recommendation endpoint accepts optional query parameters that restrict the database queryset before the vector search runs, so every attraction surfaced is guaranteed to be within the area you selected.

Overview

Geo filtering is applied inside RecommendationsListView.get_queryset() in recommendations/views.py. When a geo query parameter is present, the Django ORM adds a case-insensitive WHERE clause against the relevant indexed column on the Attraction model (county, region, or country). The vector kNN search then runs only over that filtered set, meaning the cosine-distance ranking is fully personalised within your chosen area.
Because attractions outside the selected area are excluded before the kNN query, the k parameter (number of candidates retrieved before MMR re-ranking) is scaled down proportionally — see the Effect on kNN Search section below.

Filter Hierarchy

Three query parameters are supported. Only the most specific parameter present is applied — they are evaluated in the order county → region → country, and the first match wins:
Filters attractions whose county field matches the provided value (case-insensitive). This is the most granular level available.
GET /api/recommendations/?county=Cornwall
GET /api/recommendations/?county=Kent
GET /api/recommendations/?county=Yorkshire
The priority logic in the view is:
if county_filter:
    queryset = queryset.filter(county__iexact=county_filter)
    k = 25
elif region_filter:
    queryset = queryset.filter(region__iexact=region_filter)
    k = 50
elif country_filter:
    queryset = queryset.filter(country__iexact=country_filter)
    k = 75
Providing multiple parameters (e.g. both ?county= and ?region=) will cause only the county filter to be applied; the region value is ignored.
Because a geo-filtered queryset is smaller than the full database, retrieving 100 candidates before MMR re-ranking would be wasteful — and in small counties, potentially impossible. The k value is therefore reduced proportionally with filter granularity:
Geo scopeQuery parameterCandidate pool (k)Notes
None(no filter)100Full national database
Country?country=75One of four UK countries
Region?region=50Sub-national region (e.g. South East, Midlands)
County?county=25Smallest administrative unit supported
A lower k at county level reflects the fact that many counties contain fewer than 100 unvisited attractions in the database. Passing a larger k than the filtered set size would return duplicate rows; the adjusted values are conservative enough to avoid that while still giving MMR re-ranking a meaningful candidate pool to work with.
DB indexes on county, region, and country (idx_county, idx_region, idx_country) mean the geo filter WHERE clause is evaluated efficiently before the pgvector cosine scan, keeping query latency low even for large datasets.

UK Geography Levels

The three filter levels correspond to the real administrative geography of the United Kingdom:

Countries

The four constituent countries: England, Scotland, Wales, and Northern Ireland. Use ?country= to browse attractions across an entire nation.

Regions

Sub-national groupings within each country — for example South East, North West, Yorkshire and The Humber, or Highlands in Scotland. Use ?region= to focus on a broad travel corridor.

Counties

The most granular level: traditional or ceremonial counties such as Cornwall, Kent, Cumbria, or Pembrokeshire. Use ?county= when planning a specific local trip.

Usage Examples

curl -X GET \
  "https://api.example.com/api/recommendations/?county=Cornwall" \
  -H "Authorization: Bearer <your_access_token>"
All requests require a valid JWT bearer token obtained from POST /api/user/token/.

Frontend Integration

The React Native (Expo) frontend stores the active geo filter as a query-string fragment in AsyncStorage under the key geoFilter. The getRecommendations() function in frontend/api/attraction.ts reads this value and appends it directly to the request URL:
export async function getRecommendations() {
  const geoFilter = (await AsyncStorage.getItem('geoFilter')) ?? '';
  const response = await axiosInstance.get(`/recommendations${geoFilter}`);
  return response.data;
}
The stored value is a URL query string such as ?county=Cornwall or ?region=South+East. An empty string ('') means no filter is applied. This value is written by the Geo Area Picker screen (GeoAreaPickerScreen.tsx), which presents a dropdown to select the filter level (Country / Region / County) and a list to pick the specific area.
// Written in GeoAreaPickerScreen when the user confirms their selection
const area = selectedArea ? `?${curView}=${selectedArea}` : '';
await AsyncStorage.setItem('geoFilter', area);
The geo filter is stored locally on the device in AsyncStorage. Changing it in the Settings screen writes the new value immediately, but the updated filter only takes effect on the next recommendations fetch — the current swipe deck is not refreshed mid-session.

Build docs developers (and LLMs) love