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) | Label | Tag + meta_key |
|---|---|---|
swimming_pool | Swimming Pool | amenity_swimming_pool |
free_wifi | Free WiFi | amenity_free_wifi |
free_parking | Free Parking | amenity_free_parking |
paid_parking | Paid Parking | amenity_paid_parking |
fitness_center_gym | Fitness Center / Gym | amenity_fitness_center_gym |
restaurant | Restaurant | amenity_restaurant |
bar_lounge | Bar / Lounge | amenity_bar_lounge |
airport_shuttle | Airport Shuttle | amenity_airport_shuttle |
spa_wellness | Spa & Wellness | amenity_spa_wellness |
conference_rooms | Conference Rooms | amenity_conference_rooms |
business_center | Business Center | amenity_business_center |
laundry_service | Laundry Service | amenity_laundry_service |
concierge | Concierge | amenity_concierge |
room_service_24hr | Room Service (24hr) | amenity_room_service_24hr |
free_breakfast | Free Breakfast | amenity_free_breakfast |
rooftop_terrace | Rooftop Terrace | amenity_rooftop_terrace |
kids_club | Kids' Club | amenity_kids_club |
luggage_storage | Luggage Storage | amenity_luggage_storage |
24hr_front_desk | 24hr Front Desk | amenity_24hr_front_desk |
gift_shop | Gift Shop | amenity_gift_shop |
wheelchair_accessible | Wheelchair Accessible | amenity_wheelchair_accessible |
cctv | CCTV | amenity_cctv |
elevator_lift | Elevator / Lift | amenity_elevator_lift |
security | Security | amenity_security |
pet_friendly | Pet friendly | amenity_pet_friendly |
air_conditioning | Air conditioning | amenity_air_conditioning |
kitchen | Kitchen | amenity_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.
| Slug | Label |
|---|---|
free_wifi | Free WiFi |
air_conditioning | Air Conditioning |
flat_screen_tv | Flat Screen TV |
mini_bar | Mini Bar |
room_service_24hr | Room Service (24hr) |
How to build the tick UI
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: selectedSlugson MiddlewarePOST/PUT .../properties(or room). - Marketplace search:
?amenities=swimming_pool,free_parking(slugs, comma). Winner: Marketplace and Search. - Edit: pre-tick from
amenity_* === "true"orextra_data.amenitiesslugs. Accept legacy labels once: map"Free WiFi"→free_wifithen persist slugs.
Do not assign IDOR to this list. Public browse key is public. Filtering is Middleware + Core indexes.