Skip to content

Frontend — local amenity tick list ​

Hard-code this list in Frontend — Marketplace (search filters) and Frontend — Extranet / MelonQ (property / room pickers). Do not fetch amenities from Core or Middleware. Do not persist display labels. Greenfield API content draft keeps this rule.

Copy the same module into both apps (e.g. lib/amenity-catalog.ts). Picker id, search query, and Middleware amenities[] are the slug. Label is UI only.

Canonical meta/tag on Core: amenity_{slug} and tag amenity_{slug}. Full index: Search indexes.

Drift: Extranet today stores labels ("Free WiFi"). Guest filters send wifi / pool. Middleware AND is exact match — those miss. Switch both to slugs below.


Property facilities (Marketplace filters + Extranet property picker) ​

AmenitiesPicker type="property" and STAY_AMENITY_OPTIONS must share these ids.

Slug (id / API)LabelTag + meta_key
swimming_poolSwimming Poolamenity_swimming_pool
free_wifiFree WiFiamenity_free_wifi
free_parkingFree Parkingamenity_free_parking
paid_parkingPaid Parkingamenity_paid_parking
fitness_center_gymFitness Center / Gymamenity_fitness_center_gym
restaurantRestaurantamenity_restaurant
bar_loungeBar / Loungeamenity_bar_lounge
airport_shuttleAirport Shuttleamenity_airport_shuttle
spa_wellnessSpa & Wellnessamenity_spa_wellness
conference_roomsConference Roomsamenity_conference_rooms
business_centerBusiness Centeramenity_business_center
laundry_serviceLaundry Serviceamenity_laundry_service
conciergeConciergeamenity_concierge
room_service_24hrRoom Service (24hr)amenity_room_service_24hr
free_breakfastFree Breakfastamenity_free_breakfast
rooftop_terraceRooftop Terraceamenity_rooftop_terrace
kids_clubKids' Clubamenity_kids_club
luggage_storageLuggage Storageamenity_luggage_storage
24hr_front_desk24hr Front Deskamenity_24hr_front_desk
gift_shopGift Shopamenity_gift_shop
wheelchair_accessibleWheelchair Accessibleamenity_wheelchair_accessible
cctvCCTVamenity_cctv
elevator_liftElevator / Liftamenity_elevator_lift
securitySecurityamenity_security
pet_friendlyPet friendlyamenity_pet_friendly
air_conditioningAir conditioningamenity_air_conditioning
kitchenKitchenamenity_kitchen

Marketplace filter sheet can show a subset (wifi, pool, parking, gym, …) but the id must be the slug (free_wifi, swimming_pool, free_parking), never wifi / pool.

Google Place types map to slugs (swimming_pool → swimming_pool, wifi → free_wifi), not to labels.

Onboarding seed slugs: hotel free_wifi, 24hr_front_desk, security, cctv, luggage_storage; shortlet free_wifi, security, cctv.


Room amenities (Extranet room picker only) ​

Not a Marketplace property filter unless product later searches “room has X” in Middleware.

SlugLabel
free_wifiFree WiFi
air_conditioningAir Conditioning
flat_screen_tvFlat Screen TV
mini_barMini Bar
room_service_24hrRoom Service (24hr)

How to build the tick UI ​

ts
export const PROPERTY_AMENITIES = [
  { slug: "swimming_pool", label: "Swimming Pool", scope: "property" },
  { slug: "free_wifi", label: "Free WiFi", scope: "property" },
  // …
] as const;

export function amenityTag(slug: string) {
  return `amenity_${slug}`;
}
  • Extranet save: amenities: selectedSlugs on Middleware POST/PUT .../properties (or room).
  • Marketplace search: ?amenities=swimming_pool,free_parking (slugs, comma). Winner: Marketplace and Search.
  • Edit: pre-tick from amenity_* === "true" or extra_data.amenities slugs. Accept legacy labels once: map "Free WiFi" → free_wifi then persist slugs.

Do not assign IDOR to this list. Public browse key is public. Filtering is Middleware + Core indexes.

API-first. Middleware Backend wins over Core Backend when both exist.