Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Dynamic Homepage and Personalization

Description / Background

Get personalized item recommendations based on the specific user you select. With this use case, Amazon Personalize automatically filters out items that the user purchased based on Purchase events and also the userId that you specify.

We expect that the result will be different for each user with the “Dynamic Homepage Personalization” feature. The difference will be based upon searches, views, country, and bookings on our platform.

Glossary

https://app.clickup.com/9003122396/docs/8ca1fpw-35796/8ca1fpw-41516

Objectives

  • User can find their personalized recommendation on the Recommended For You section
  • We use AWS Recommended For You for the system
  • Phase 1:
    • Registered user feature:
      • User can see the customized restaurant list on Recommended For You
      • Get user behavior data from restaurant view and booking
  • Phase 2:
    • Adding recommendation based on user country
    • The default country will be Bangkok for user outside Thailand or Singapore
    • Rewrite the API from REST to GraphQL
    • Add new country parameters when the user is not from Thailand or Singapore
    • Add cache on app layer using Aiven
    • Change the transaction database from PostgreSQL to Aiven
    • Use Cloudflare R2 for object storage
    • Add Nuxt Tailwind template for the admin dashboard

Scope

Homepage, Restaurant detail page

Sequence Diagram / Flow

Flow Homepage Personalization:

Backend Implementation

  • Created hh-felidae monorepo using Turborepo with microservices architecture containing Jaguar (admin dashboard), Puma (search API), and Tiger (backend API) applications
  • Implemented comprehensive admin dashboard using Nuxt.js 3 with vue-shadcn/ui, TailwindCSS, TanStack Query Vue for data fetching, and URQL GraphQL client
  • Built homepage management system with full CRUD operations for homepages, sections, banners, home icons, and tag sections with drag-and-drop reordering
  • Implemented TranslationManager component for multi-language content management across all entities
  • Created reusable UI components including file upload with drag-and-drop, city selector with multi-select, and dynamic form validation using vee-validate and Zod
  • Set up GraphQL API using Fastify and Mercurius with auto-generated TypeScript types from centralized schema definitions
  • Implemented Drizzle ORM with multi-database support (db1: external, db2: data warehouse, db3: core application) with separate configurations
  • Created BullMQ job queue system with Redis for async background processing and data pipeline tasks
  • Integrated OpenSearch for search and analytics capabilities with proper indexing and query support
  • Set up Apache Kafka for event streaming and real-time data pipeline processing
  • Implemented Better Auth authentication solution across all services for secure admin and API access
  • Configured AWS SDK integration for cloud services and file storage operations
  • Created comprehensive seed data system with Faker.js for development and testing environments
  • Set up Docker Compose local development infrastructure with Redis, Kafka, OpenSearch, and OpenSearch Dashboard services
  • Implemented environment configuration validation using env-schema with proper type safety
  • Created Metarank ML-powered personalization engine integration for restaurant recommendations
  • Set up GrowthBook feature flagging platform for A/B testing and gradual feature rollouts
  • Implemented hh-personalize GraphQL API service using Fastify with Amazon Personalize integration for “Recommended For You” functionality
  • Created event tracking system for user behavior (restaurant views, bookings, purchases) to feed AWS Personalize training datasets
  • Set up index reset and data reseeding utilities for OpenSearch restaurant data management
  • Configured proper CORS, authentication plugins, and caching strategies across all Fastify services
  • Implemented file-based routing in Nuxt with middleware for route protection and user session management
  • Added jaguar_host admin setting in hh-server AdminSetting model with default URL configuration and documentation for Jaguar dashboard host
  • Implemented URL normalization method in AdminSetting to handle trailing slashes and whitespace for safe Jaguar host URLs
  • Updated admin navbar in hh-server to redirect “Homepage Setting” menu link to Jaguar dashboard /homepages route when jaguar_host is configured
  • Configured external link security with noopener noreferrer attributes and new tab opening for Jaguar dashboard links
  • Implemented fallback to internal restaurant sections path when Jaguar host is not configured in admin settings

PR #5 - Feat/homepage-dashboard

PR #7427 - homepage setting redirect url

hh-personalize Repository

AWS Personalize - Recommended For You

Frontend Implementation

  • Added NUXT_PUBLIC_PERSONALIZE_DOMAIN environment variable in .env.example for personalization service configuration
  • Created RecommendedForYou.vue component (34 lines) for displaying personalized restaurant recommendations section
  • Implemented RecommendedForYouView.vue (156 lines) with complete logic for fetching and rendering recommended restaurants using GraphQL
  • Integrated “Recommended For You” section into HomeBody.astro homepage template with conditional rendering for logged-in users and tag section support
  • Added getRecommendedForYouGraphql.ts API module (133 lines) with GraphQL queries for fetching personalized restaurant data from hh-personalize service
  • Created personalized GraphQL client in urql.ts with dedicated configuration for personalization domain and proper authentication headers, consolidated to createTigerUrqlClient for unified access
  • Updated GraphQL client configurations for getRestaurantTagsGraphql.ts, searchSuggestionGraphql.ts, and searchRestaurantGraphql.ts to use modular client creation
  • Implemented session ID management utility in sessionId.ts (25 lines) with localStorage persistence and UUID generation for tracking user sessions
  • Added SESSION_ID_KEY constant to constants.ts for consistent session storage key across the application
  • Created comprehensive event tracking system in trackEvents.ts (44 lines) with support for VIEW and PURCHASE event types to AWS Personalize
  • Implemented baseTrackEvents.ts (27 lines) base function for sending personalized events to hh-personalize API with proper payload formatting, updated to use Tiger URQL client
  • Enhanced BookingConfirmation.vue to integrate user tracking for completed purchase events with session ID and user ID, migrated to use HH-Tiger banner API and HomeBanner type
  • Added user behavior tracking to RestaurantDetailEntry.vue (14 lines) for capturing restaurant view events with restaurant ID, user ID, and session ID
  • Defined TypeScript event types in EventType.ts (33 lines) including PersonalizeEventInput, ViewEvent, PurchaseEvent interfaces with proper type safety
  • Configured proper error handling and validation for mandatory parameters (sessionId, userId, restaurantId) in analytics tracking functions
  • Integrated automatic event sending on restaurant detail page visits and booking confirmations to feed AWS Personalize training datasets
  • Migrated banners/icons to HH-Tiger GraphQL API, replacing old REST endpoints with GraphQL queries
  • Introduced HomeBanner interface in Banner.ts to unify banner types across components
  • Refactored getBanner.ts to implement GetBanners via Tiger GraphQL schema (+61/-88 lines)
  • Updated getDeals.ts to implement GetHomeIcons via Tiger GraphQL (+51/-70 lines)
  • Created getHomeTagSection.ts (105 lines) new API to fetch tag section items with country-aware banners
  • Added getHomepageListGraphql.ts (221 lines) with comprehensive GraphQL homepage sections APIs for fetching layout data
  • Simplified homepage cache logic by removing cache clearing in home-page.ts API (+15/-24 lines)
  • Replaced cached layout with direct GraphQL fetch in layout.ts API (+5/-64 lines)
  • Updated HomePromotion.vue to fetch promotion banners via new service with simplified props (+11/-46 lines)
  • Modified HomeTagIcon.vue to fetch home icons by cityId using global isDesktop utility (+7/-20 lines)
  • Enhanced BenefitPromos.vue to migrate member promos to section banner GraphQL (+27/-40 lines)
  • Updated PromotionCard.vue to adapt to HomeBanner image fields (+4/-7 lines)
  • Refactored homeSection.ts service to use GraphQL for promotions/icons with HomeBanner integration (+15/-25 lines)
  • Added HH-Tiger fallback for group landing data in groupLanding.ts service (+102/-12 lines)
  • Updated server-side rendering components: Home.astro to use hero banner via GraphQL with countryCode (+32/-53 lines), HomePromotion.astro to server-fetch promotions (+55/-12 lines), HomeTagIcon.astro to server-fetch icons by cityId (+6/-20 lines)
  • Created TopCuisineSorted.astro (48 lines) component to render sorted tag section
  • Simplified HomeBanner.astro props to use direct URLs (+7/-19 lines)
  • Updated url.ts utility to skip CDN rewrite for tiger-hosted assets
  • Modified growthbook.ts to switch GrowthBook events to Tiger URQL client
  • Removed deprecated layout cookie cleanup from middleware.ts

PR #1363 - personalization v2 CU-86cx6d57u

PR #2280 - tiger homepage new

PRD & Task

https://app.clickup.com/t/86cx5qhc1

https://app.clickup.com/t/86cza5hjz Dynamic homepage PRD: https://docs.google.com/document/d/1MgRrTpqVCJA0Oa0QmkBsJn-IvSvjp9iaEhJTFccb_44/edit

API Blueprint

How to get Grapghql query:

MethodPathURLDescriptionPayload
GET/graphqlstaging: https://hh-personalize.hh-engineering.my.id/get recomended for you data for registered user
POST(?)/services/analytics/track_eventsSent data event when user open detail restaurant and purchase

DB Schema / Database Migration

Database migrations are managed through hh-server and related services.

Improvement:

Feature NameDateWhat ChangedDescription
phase 13 Feb 2025initial document-