Occasion Vault (customer-facing name: The Diary ) is a profile-based occasion system that helps members remember important dates and discover relevant restaurants before those moments arrive. The goal is to turn personal occasions into timely reminders, curated discovery, and higher-intent bookings.
Current State:
Waiting to ship
Available on web and mobile web/hybrid
Native app parity not confirmed in this PRD
Markets: TH (Thailand), SG (Singapore), MY (Malaysia)
Enable customers to track and manage personal occasions (birthdays, anniversaries, cultural occasions)
Provide automatic reminders before occasions (T-14 and T-7)
Drive restaurant discovery through 3-tier waterfall resolution
Support one-tap Google Calendar export without OAuth
Birthday auto-sync from existing user profile
Add/edit/delete occasions (anniversaries, cultural occasions, custom dates)
Market-aware suggested occasions with prefilled dates
Toggle reminders on/off per occasion
T-14 and T-7 reminder emails and FCM push notifications
3-tier restaurant discovery waterfall (GLP → Tag-based fallback → Suppression)
One-tap Google Calendar export
Profile action button with GLP/fallback logic
Multi-language support (EN, TH, CN, and other locales)
Native mobile app implementation
Netcore event routing
In-app deep linking for non-Reservation/Reward content
Auto-sync the existing birthday into a Diary card without forcing setup work from the user
Let users toggle reminders on/off while keeping birthday edits anchored in Account Settings
Show market-aware suggested occasions with prefilled dates
Support anniversaries, cultural occasions, Valentine’s Day, and freeform custom dates
Provide toggle, edit, and delete behavior based on occasion type
Send T-14 and T-7 reminders for active occasions
Resolve each reminder through a 3-tier waterfall:
Tier 1: Dedicated GLP (Group Landing Page)
Tier 2: Rule-based fallback list
Tier 3: Suppression if supply is too weak
Reuse the same GLP/fallback logic for the Diary action button on each card
Support one-tap Google Calendar export without OAuth
Member profile page (desktop and mobile)
Diary section in profile navigation
Dedicated diary route
Navigate to HungryHub website or app
Access Profile page
Find Diary section
View existing occasions or add new ones
Navigate to Profile > Diary
View all saved occasions with upcoming dates
See suggested occasions based on market
Click “Add Occasion” button
Select from suggested occasions or create custom
Set date (month/day/year)
Toggle reminder on/off
Save occasion
Tap occasion card
Edit date or toggle reminder
Delete occasion if needed
Tap calendar icon on occasion card
One-tap Google Calendar event created
Occasion Reminder Triggered
│
▼
┌──────────────┐
│ Tier 1: │
│ Dedicated │
│ GLP │
└──────────────┘
│
┌──────┴──────┐
│ Has valid │
│ GLP? │
└──────┬──────┘
Yes │ No
▼ ▼
┌──────────────┐ ┌──────────────┐
│ Return GLP │ │ Tier 2: │
│ deep link │ │ Tag-based │
└──────────────┘ │ fallback │
└──────────────┘
│
┌───────┴───────┐
│ Has matching │
│ restaurants? │
└───────┬───────┘
Yes │ No
▼ ▼
┌──────────────┐ ┌──────────────┐
│ Return │ │ Tier 3: │
│ fallback │ │ Suppress │
│ deep link │ │ (no link) │
└──────────────┘ └──────────────┘
user_occasions — per-user occasion rows
occasion_type: birthday, anniversary, cultural, custom
occasion_key: unique identifier
label: custom label
month, day, year: date components
is_active: boolean
source: system, user_created
reminder_last_sent_year: for idempotency
occasion_glp_mappings — maps occasion to Group Landing Page
cultural_occasion_dates — fixed-date cultural occasions (Songkran, Loy Krathong, etc.)
occasion_fallback_rules — cascading fallback rules
AddOccasionService / EditOccasionService / DeleteOccasionService / ToggleOccasionService
ListUserOccasionsService — returns active cards + suggested occasions
SyncBirthdayOccasionService — auto-syncs birthday from users table
ListOccasionTypesService — enumerates supported occasion types
MarketResolver + ResolveOccasionService — 3-tier waterfall resolution
Method Path Description
GET /diary List user occasions
POST /diary Create occasion
PATCH /diary/:id Update occasion
DELETE /diary/:id Delete occasion
POST /diary/:id/toggle Toggle reminder
GET /diary/occasion_types List occasion types
POST /diary/calendar_link Generate Google Calendar link
GET /diary/suggested Get suggested occasions
ff_occasion_vault_v1 — gates all user-visible behavior
20260806100000_create_user_occasions.rb
20260806100001_create_occasion_glp_mappings.rb
20260806100002_create_cultural_occasion_dates.rb
20260806100003_create_occasion_fallback_rules.rb
PR: https://github.com/hungryhub-team/hh-server/pull/8644
DiarySection.vue — Responsive diary section and interaction orchestration
AddOccasion.ts — Occasion forms across modal and sheet layouts
CalendarPopup.vue — Date, month, and year picker views
fetchDiarySuggested.ts — Suggested occasion selection
occasionIcon.ts — Reusable diary cards with occasion icons
useDiaryPermissions.ts — Manage diary reminders, permissions, mobile actions
DiaryDeleteOccasionConfirm.vue — Help, tooltip, confirmation overlays
InfoBanner.vue — Diary controls, notices, loading skeletons
AddOccasionBottomSheet.vue
AddOccasionForm.vue
DiaryManageBottomSheet.vue
DiaryItemCard.vue
DiaryTurnOffRemindersConfirm.vue
useDiary.ts — Core diary state
useAddOccasionForm.ts — Form handling
useDiaryReminders.ts — Reminder management
useDiaryToggle.ts — Toggle functionality
DiaryOccasion.ts — CRUD endpoints
createDiaryOccasion.ts — Create API module
updateDiaryOccasion.ts — Update API module
deleteDiaryOccasion.ts — Delete API module
toggleDiaryOccasion.ts — Toggle API module
Desktop: Dedicated diary navigation route
Mobile: Embedded in profile page
Multi-language support (EN, TH, CN, and other locales)
Localized diary content in profile.json
PR: https://github.com/hungryhub-team/hh-pegasus/pull/3136
TBD
Method Path URL Description Payload
GET /api/v5/diary List user occasions
POST /api/v5/diary Create occasion { occasion_type, occasion_key, label, month, day, year, is_active }
PATCH /api/v5/diary/:id Update occasion { label, month, day, year, is_active }
DELETE /api/v5/diary/:id Delete occasion
POST /api/v5/diary/:id/toggle Toggle reminder { is_active }
GET /api/v5/diary/occasion_types List occasion types
POST /api/v5/diary/calendar_link Generate calendar link { occasion_id }
GET /api/v5/diary/suggested Get suggested occasions
Column Type Description
id bigint Primary key
user_id bigint Foreign key to users
occasion_type string birthday, anniversary, cultural, custom
occasion_key string Unique identifier
label string Custom label
month integer Month (1-12)
day integer Day (1-31)
year integer Year (nullable)
is_active boolean Reminder active flag
source string system, user_created
reminder_last_sent_year integer For idempotency
created_at datetime
updated_at datetime
Column Type Description
id bigint Primary key
occasion_type string
occasion_key string
glp_id bigint Foreign key to GLPs
created_at datetime
updated_at datetime
Column Type Description
id bigint Primary key
occasion_key string Unique identifier
name string Display name
month integer
day integer
created_at datetime
updated_at datetime
Column Type Description
id bigint Primary key
occasion_type string
country_id bigint
tags text[] Fallback tags
created_at datetime
updated_at datetime
Feature Name Date What Changed Description
Occasion Vault 2026-09 Initial Release New profile-based occasion system with reminders and restaurant discovery
Customer-facing name is The Diary ; Occasion Vault is only the internal working name
No design link provided in the PRD