C1 — Frontend Telemetry Event Dictionary
Scope: The single sortable list of every frontend-emitted telemetry event for Ghasi Melmastoon across all surfaces (web, mobile, desktop, kiosk, tablet). Each event maps to a journey step, a workflow, and a surface. Analytics, RUM, and observability pipelines consume from this catalog.
Instrumentation: All events are emitted via
@ghasi/telemetry(wraps OpenTelemetry + web-vitals). Web events flow to the BFF overPOST /telemetry/v1/events(batched, sampled). Mobile uses the same JSON schema over the React Native bridge. Desktop uses the OTel SDK Node binding in the main process. Kiosk mirrors desktop telemetry.Privacy: No PII in event properties. Guest identity is represented only as
gms_id(pseudonymous UUID keyed to the BFF session). Reservation IDs and property IDs are permitted. Payment instrument details are never logged.
1. Schema (all events)
interface MelmastoonTelemetryEvent {
event_name: string; // kebab-case, namespaced: "mel.<surface>.<noun>.<verb>"
event_version: string; // semver e.g. "1.0.0"
timestamp_ms: number; // Unix epoch ms
session_id: string; // BFF-issued session UUID
surface: Surface; // see §2
journey_id?: string; // "J-01" .. "J-22"
workflow_id?: string; // "W-01" .. "W-12"
tenant_id?: string; // present when in-tenant context
property_id?: string;
correlation_id?: string; // traceparent propagated from BFF
user_agent?: string; // stripped to browser family + major version
locale: string; // BCP 47 e.g. "ps-AF"
dir: "ltr" | "rtl";
properties: Record<string, string | number | boolean | null>;
}
type Surface = "consumer-web" | "tenant-booking-web" | "guest-portal-web" |
"control-plane-web" | "ota-portal-web" |
"consumer-mobile" | "staff-mobile" |
"operator-desktop" | "kiosk" | "tablet-pos";
2. Event catalog
2.1 Discovery & Search (J-01, W-01)
| # | Event name | Version | Trigger | Key properties | Surface(s) |
|---|---|---|---|---|---|
| D-01 | mel.consumer.search.executed | 1.0.0 | User submits search (tap/click or URL navigation) | query_type (text/map/filter), destination, check_in, check_out, adult_count, room_count, filter_count, result_count, latency_ms | consumer-web, consumer-mobile |
| D-02 | mel.consumer.search.results_rendered | 1.0.0 | Results list/map mounts with data | result_count, render_mode (list/map), above_fold_count, latency_ms | consumer-web, consumer-mobile |
| D-03 | mel.consumer.search.filter_applied | 1.0.0 | User applies or removes a filter chip | filter_key, filter_value, result_count_after | consumer-web, consumer-mobile |
| D-04 | mel.consumer.search.sort_changed | 1.0.0 | User changes sort order | sort_key (price_asc / distance / popularity / rating), result_count | consumer-web, consumer-mobile |
| D-05 | mel.consumer.property.card_clicked | 1.0.0 | Guest taps a property card in list or map | property_id, rank_position, render_mode, min_rate_afn | consumer-web, consumer-mobile |
| D-06 | mel.consumer.property.detail_viewed | 1.0.0 | Property detail page/screen mounts | property_id, photo_count, rate_count, latency_ms | consumer-web, consumer-mobile |
| D-07 | mel.consumer.property.shortlisted | 1.0.0 | Guest adds to shortlist/wishlist | property_id, shortlist_size, storage_type (cookie/account) | consumer-web, consumer-mobile |
| D-08 | mel.consumer.property.shortlist_removed | 1.0.0 | Guest removes from shortlist | property_id, shortlist_size | consumer-web, consumer-mobile |
| D-09 | mel.consumer.map.pin_hovered | 1.0.0 | Guest hovers/long-presses a map pin | property_id, rank_position | consumer-web, consumer-mobile |
| D-10 | mel.consumer.search.no_results | 1.0.0 | Search returns 0 results | destination, check_in, check_out, filter_count | consumer-web, consumer-mobile |
2.2 Booking Handoff (J-02, W-02)
| # | Event name | Version | Trigger | Key properties | Surface(s) |
|---|---|---|---|---|---|
| H-01 | mel.consumer.handoff.initiated | 1.0.0 | Guest taps "Book" on property detail | property_id, tenant_id, source (list/map/detail) | consumer-web, consumer-mobile |
| H-02 | mel.tenant.bootstrap.completed | 1.0.0 | Tenant theme + policy bootstrap resolves | tenant_id, theme_version, latency_ms, locale | tenant-booking-web, consumer-mobile |
| H-03 | mel.tenant.bootstrap.failed | 1.0.0 | Bootstrap error | tenant_id, error_code, retry_count | tenant-booking-web, consumer-mobile |
2.3 Booking Funnel (J-03, J-04, W-03, W-04)
| # | Event name | Version | Trigger | Key properties | Surface(s) |
|---|---|---|---|---|---|
| B-01 | mel.booking.funnel.step_viewed | 1.0.0 | Funnel step screen mounts | step (room_select/rate_select/guest_details/payment/confirm), tenant_id, property_id | tenant-booking-web, consumer-mobile |
| B-02 | mel.booking.funnel.step_completed | 1.0.0 | User advances to next step | step, duration_ms, tenant_id | tenant-booking-web, consumer-mobile |
| B-03 | mel.booking.funnel.step_abandoned | 1.0.0 | User exits mid-funnel | step, duration_ms, tenant_id | tenant-booking-web, consumer-mobile |
| B-04 | mel.booking.room.selected | 1.0.0 | Guest selects a room type | property_id, room_type_id, rate_plan_id, nights, rate_afn | tenant-booking-web, consumer-mobile |
| B-05 | mel.booking.rate.selected | 1.0.0 | Guest selects a rate plan | rate_plan_id, rate_plan_type, total_afn, cancellation_policy | tenant-booking-web, consumer-mobile |
| B-06 | mel.booking.payment_method.selected | 1.0.0 | Guest selects payment method | method (cash_on_arrival/card/mobile_money), tenant_id | tenant-booking-web, consumer-mobile |
| B-07 | mel.booking.payment.3ds_started | 1.0.0 | 3DS challenge iframe mounts | tenant_id, amount_afn, currency | tenant-booking-web, consumer-mobile |
| B-08 | mel.booking.payment.3ds_completed | 1.0.0 | 3DS challenge resolves | tenant_id, outcome (success/fail/timeout) | tenant-booking-web, consumer-mobile |
| B-09 | mel.booking.confirmation.shown | 1.0.0 | Confirmation screen mounts | reservation_id, tenant_id, payment_method, total_afn, nights | tenant-booking-web, consumer-mobile |
| B-10 | mel.booking.confirmation.receipt_downloaded | 1.0.0 | Guest downloads receipt PDF | reservation_id, tenant_id | tenant-booking-web, consumer-mobile |
| B-11 | mel.booking.error.payment_failed | 1.0.0 | Payment error shown | error_code, tenant_id, method | tenant-booking-web, consumer-mobile |
| B-12 | mel.booking.error.availability_changed | 1.0.0 | Room no longer available after hold | tenant_id, property_id, room_type_id | tenant-booking-web, consumer-mobile |
| B-13 | mel.booking.hold.acquired | 1.0.0 | BFF issues hold | hold_id, expires_at, tenant_id | tenant-booking-web, consumer-mobile |
| B-14 | mel.booking.hold.expired | 1.0.0 | Hold timer reaches 0 before confirm | hold_id, tenant_id, step | tenant-booking-web, consumer-mobile |
2.4 Front Desk / Backoffice (J-05 to J-12, W-05 to W-10)
| # | Event name | Version | Trigger | Key properties | Surface(s) |
|---|---|---|---|---|---|
| FD-01 | mel.desk.checkin.initiated | 1.0.0 | Clerk opens check-in modal | reservation_id, tenant_id, source (arrivals_board/search) | operator-desktop |
| FD-02 | mel.desk.checkin.completed | 1.0.0 | Reservation moves to checked_in | reservation_id, duration_ms, payment_method | operator-desktop |
| FD-03 | mel.desk.key.issued | 1.0.0 | Key credential issued | reservation_id, key_type (mobile/pin/card), vendor | operator-desktop, kiosk |
| FD-04 | mel.desk.key.issue_failed | 1.0.0 | Key issuance failed | reservation_id, key_type, vendor, error_code | operator-desktop, kiosk |
| FD-05 | mel.desk.checkout.completed | 1.0.0 | Reservation moves to checked_out | reservation_id, folio_total_afn, settlement_method, duration_ms | operator-desktop |
| FD-06 | mel.desk.walkin.booking_created | 1.0.0 | Walk-in booking saved (online or offline) | reservation_id, offline (bool), payment_method, rooms, nights | operator-desktop |
| FD-07 | mel.desk.room_move.completed | 1.0.0 | Room reassignment saved | reservation_id, old_room_id, new_room_id | operator-desktop |
| FD-08 | mel.desk.folio.charge_added | 1.0.0 | Charge posted to folio | reservation_id, charge_type, amount_afn | operator-desktop |
| FD-09 | mel.desk.folio.refund_issued | 1.0.0 | Refund approved and applied | reservation_id, amount_afn, approval_role | operator-desktop |
| FD-10 | mel.desk.eod.drawer_closed | 1.0.0 | EOD cash drawer close submitted | tenant_id, expected_afn, actual_afn, variance_afn, shift_id | operator-desktop |
| FD-11 | mel.desk.eod.report_exported | 1.0.0 | EOD report PDF exported | tenant_id, report_type, shift_id | operator-desktop |
| FD-12 | mel.desk.registration.submitted | 1.0.0 | Daily guest registration submitted to authority | tenant_id, guest_count, date, authority_endpoint | operator-desktop |
| FD-13 | mel.desk.sync.pull_completed | 1.0.0 | Sync pull round-trip completes | tenant_id, records_received, latency_ms, conflict_count | operator-desktop |
| FD-14 | mel.desk.sync.conflict_resolved | 1.0.0 | User resolves a sync conflict | aggregate_type, strategy (keep_local/keep_remote/manual), tenant_id | operator-desktop |
| FD-15 | mel.desk.offline.mode_entered | 1.0.0 | App detects network loss | tenant_id, last_sync_at | operator-desktop |
| FD-16 | mel.desk.offline.mode_exited | 1.0.0 | App reconnects and triggers sync | tenant_id, offline_duration_ms, outbox_queue_size | operator-desktop |
2.5 Housekeeping (J-19 to J-22, W-08)
| # | Event name | Version | Trigger | Key properties | Surface(s) |
|---|---|---|---|---|---|
| HK-01 | mel.hk.task.viewed | 1.0.0 | Housekeeper views task detail | task_id, room_id, tenant_id | operator-desktop, kiosk, staff-mobile |
| HK-02 | mel.hk.task.status_updated | 1.0.0 | Room status changed (dirty→cleaning→clean) | task_id, room_id, old_status, new_status, offline | operator-desktop, kiosk, staff-mobile |
| HK-03 | mel.hk.task.maintenance_escalated | 1.0.0 | Housekeeper raises maintenance ticket | task_id, room_id, issue_type, photo_attached | operator-desktop, kiosk, staff-mobile |
| HK-04 | mel.hk.board.reordered | 1.0.0 | Lead manually re-orders board (overriding AI suggestion) | tenant_id, moved_task_id, ai_override | operator-desktop |
| HK-05 | mel.hk.ai_suggestion.accepted | 1.0.0 | Lead accepts AI-suggested task order | tenant_id, suggestion_id, tasks_affected | operator-desktop |
| HK-06 | mel.hk.ai_suggestion.rejected | 1.0.0 | Lead rejects or ignores AI suggestion | tenant_id, suggestion_id, reason_code | operator-desktop |
2.6 Management & AI (J-13 to J-18, W-09, W-11)
| # | Event name | Version | Trigger | Key properties | Surface(s) |
|---|---|---|---|---|---|
| MG-01 | mel.mgmt.pricing.ai_suggestion_shown | 1.0.0 | AI pricing suggestion surfaces in GM view | suggestion_id, room_type_id, suggested_rate_afn, delta_pct, model, local | operator-desktop |
| MG-02 | mel.mgmt.pricing.ai_suggestion_accepted | 1.0.0 | GM accepts suggestion | suggestion_id, room_type_id, review_ms | operator-desktop |
| MG-03 | mel.mgmt.pricing.ai_suggestion_rejected | 1.0.0 | GM rejects suggestion | suggestion_id, reason_code | operator-desktop |
| MG-04 | mel.mgmt.dashboard.kpi_viewed | 1.0.0 | Daily ops dashboard mounts | tenant_id, date, occupancy_pct, adr_afn, arrivals_count | operator-desktop |
| MG-05 | mel.mgmt.report.tax_exported | 1.0.0 | Monthly tax report exported | tenant_id, period, format (pdf/csv) | operator-desktop |
| MG-06 | mel.mgmt.tenant.onboarding_step_completed | 1.0.0 | Super-admin completes an onboarding step | tenant_id, step, duration_ms | control-plane-web |
| MG-07 | mel.mgmt.theme.preview_opened | 1.0.0 | Theme preview opened in control plane | tenant_id, theme_version_draft | control-plane-web |
| MG-08 | mel.mgmt.theme.published | 1.0.0 | Theme publish submitted | tenant_id, theme_version | control-plane-web |
| MG-09 | mel.mgmt.theme.rolled_back | 1.0.0 | Theme rolled back to previous version | tenant_id, rolled_back_to_version | control-plane-web |
2.7 AI provenance events (cross-surface)
| # | Event name | Version | Trigger | Key properties | Surface(s) |
|---|---|---|---|---|---|
| AI-01 | mel.ai.suggestion.rendered | 1.0.0 | Any AI suggestion component mounts | suggestion_id, model, version, prompt_id, local (bool), surface | all |
| AI-02 | mel.ai.suggestion.accepted | 1.0.0 | Human accepts suggestion | suggestion_id, review_ms | all |
| AI-03 | mel.ai.suggestion.rejected | 1.0.0 | Human rejects suggestion | suggestion_id, reason_code | all |
| AI-04 | mel.ai.suggestion.timeout | 1.0.0 | Suggestion timeout (model too slow) | suggestion_id, waited_ms, fallback | all |
| AI-05 | mel.ai.inference.local_completed | 1.0.0 | ONNX local inference completes | model, version, latency_ms, first_token_ms | operator-desktop |
| AI-06 | mel.ai.inference.cloud_completed | 1.0.0 | Cloud AI inference completes | model, version, latency_ms, tokens_in, tokens_out | all |
2.8 Core Web Vitals + performance (web + mobile)
| # | Event name | Version | Trigger | Key properties | Surface(s) |
|---|---|---|---|---|---|
| P-01 | mel.web.vitals.lcp | 1.0.0 | web-vitals LCP callback | value_ms, rating (good/needs-improvement/poor), route, tenant_id | consumer-web, tenant-booking-web |
| P-02 | mel.web.vitals.inp | 1.0.0 | web-vitals INP callback | value_ms, rating, route, tenant_id | consumer-web, tenant-booking-web |
| P-03 | mel.web.vitals.cls | 1.0.0 | web-vitals CLS callback | value, rating, route | consumer-web, tenant-booking-web |
| P-04 | mel.web.vitals.ttfb | 1.0.0 | web-vitals TTFB callback | value_ms, rating, route | consumer-web, tenant-booking-web |
| P-05 | mel.mobile.startup.cold | 1.0.0 | React Native app reaches interactive | duration_ms, locale, surface | consumer-mobile, staff-mobile |
| P-06 | mel.desktop.startup.cold | 1.0.0 | Electron reaches first paint | duration_ms, tenant_id | operator-desktop |
3. Sampling policy
| Tier | Default sample rate | Override |
|---|---|---|
| Core Web Vitals | 100% | — |
| Booking funnel steps | 100% | — |
| AI suggestion events | 100% | — |
| Search executed (authenticated) | 100% | — |
| Search executed (anonymous) | 1% | Feature flag TELEMETRY_SEARCH_ANON_RATE |
| Map pin hover, card scroll | 10% | Feature flag TELEMETRY_INTERACTION_RATE |
| HK task views | 100% (staff) | — |
| Desktop sync events | 100% | — |
4. Retention
| Event group | Retention |
|---|---|
| Booking funnel, confirmation, payment | 365 days (compliance) |
| AI suggestion events | 180 days |
| Core Web Vitals | 90 days |
| Search, map, interaction | 30 days |
| Desktop sync, offline events | 90 days |
5. Open Questions
- Should
mel.consumer.search.executedinclude raw query text (filtered for PII) for ML training, or only structured fields? - Should we add a
mel.booking.funnel.funnel_idproperty to correlate abandoned + resumed sessions across page reloads? - Desktop sync events: should
latency_msinclude the outbox flush time or only the network round-trip?
References
09-non-functional-requirements.md§5 (Observability)05-frontend-workflows.md§1 (Workflow index)../journeys/README.md../../04-event-driven-architecture.md