C5 — Feature Flag Inventory
Scope: Every feature flag that the Ghasi Melmastoon frontend checks, including: per-tenant toggles resolved from
theme-config-service, global platform flags from the BFF bootstrap, and local dev/CI flags. Flags control UI availability, experimental features, and A/B variants.Source: Collated from
useFeatureFlagreferences, tenant toggles in06-theming-and-tenant-config.mdsection 17, and BFF bootstrap payload.Rule: No hard-coded
if (ENV === "prod")conditionals. All feature gating goes through this catalog and theuseFeatureFlaghook. Adding a new flag requires adding it here first.
1. Flag resolution hierarchy
1. Local override (dev/.env.local, CI) ← highest priority
2. BFF bootstrap payload flag ← platform-wide or tenant-wide
3. Tenant config (theme-config-service toggle) ← tenant-specific
4. Global default (code default) ← lowest priority
Flags are loaded at app boot from GET /bff/bootstrap and cached in React Query with a 5-minute TTL. On desktop, flags are part of the sync pull payload and stored in local SQLite.
2. Flag schema
interface FeatureFlag {
key: string; // kebab-case, e.g. "consumer-map-view"
scope: FlagScope; // "global" | "tenant" | "property" | "user-role"
type: "boolean" | "string" | "number";
defaultValue: boolean | string | number;
description: string;
surfaces: Surface[];
phase: "R1" | "R2" | "R3" | "experimental";
killSwitch?: boolean; // true = flag disables feature if false (vs hides it)
}
3. Platform-wide flags (resolved from BFF bootstrap)
| Flag key | Type | Default | Phase | Description | Surface(s) |
|---|---|---|---|---|---|
consumer-map-view | boolean | true | R1 | Enable map view on consumer meta search (Leaflet). Disable to fall back to list-only if map tiles are slow. | consumer-web, consumer-mobile |
consumer-shortlist-max | number | 10 | R1 | Max items a guest can shortlist before being prompted to log in. | consumer-web, consumer-mobile |
booking-hold-timeout-minutes | number | 15 | R1 | How long an inventory hold lasts before expiry. Surfaced as countdown timer. | tenant-booking-web, consumer-mobile |
booking-card-3ds | boolean | true | R1 | Enable Adyen 3DS2 challenge step. Disable for card processors that don't require 3DS. | tenant-booking-web, consumer-mobile |
booking-apple-pay | boolean | false | R2 | Enable Apple Pay button in payment step. | tenant-booking-web, consumer-mobile |
booking-google-pay | boolean | false | R2 | Enable Google Pay button. | tenant-booking-web, consumer-mobile |
booking-mobile-money | boolean | false | R2 | Enable mobile money (e.g., M-Pesa, easypaisa) as a payment option. | tenant-booking-web, consumer-mobile |
desktop-ai-copilot | boolean | false | R2 | Enable operator copilot AI sidebar (HITL suggestions for pricing, ops). | operator-desktop |
desktop-sync-push-interval-seconds | number | 30 | R1 | How frequently the desktop pushes outbox changes to BFF. | operator-desktop |
desktop-lock-offline-pin-fallback | boolean | true | R1 | Allow PIN-based offline key fallback when lock vendor is unreachable. | operator-desktop |
desktop-auto-update-prompt | boolean | true | R1 | Show auto-update banner when a new version is available. | operator-desktop |
opensearch-meta-search | boolean | false | R2 | Route meta search to OpenSearch index (vs Postgres FTS). Toggle after R2 index is warm. | consumer-web, consumer-mobile |
telemetry-search-anon-rate | number | 0.01 | R1 | Sampling rate (0–1) for anonymous search telemetry events. | consumer-web, consumer-mobile |
telemetry-interaction-rate | number | 0.10 | R1 | Sampling rate for hover/scroll/map-pin interactions. | consumer-web, consumer-mobile |
guest-portal | boolean | false | R2 | Enable the /manage guest portal (mid-stay / post-stay) for tenants. | guest-portal-web |
mobile-key-ble | boolean | false | R3 | Enable BLE mobile key (requires Wallet entitlement and lock vendor BLE SDK). | consumer-mobile, staff-mobile |
mobile-key-wallet | boolean | false | R3 | Enable Apple/Google Wallet key pass provisioning. | consumer-mobile |
kiosk-self-checkin | boolean | false | R2 | Enable self-check-in kiosk mode (Electron kiosk). | kiosk |
ota-portal | boolean | false | R3 | Enable OTA partner portal surface. | ota-portal-web |
embed-widget | boolean | false | R2 | Enable embeddable booking widget for tenant external sites. | — |
4. Per-tenant toggles (from theme-config-service tenant config)
| Flag key | Type | Default | Description | Surface(s) |
|---|---|---|---|---|
tenant.booking-flow.special-requests | boolean | true | Show special requests step in booking funnel. | tenant-booking-web, consumer-mobile |
tenant.booking-flow.company-booking | boolean | false | Enable company/corporate booking fields (company name, VAT number). | tenant-booking-web |
tenant.booking-flow.loyalty-code | boolean | false | Show loyalty/promo code input in funnel. | tenant-booking-web, consumer-mobile |
tenant.booking-flow.child-policy | boolean | true | Show child age capture in guest-details step. | tenant-booking-web, consumer-mobile |
tenant.payment.cash-on-arrival | boolean | true | Offer cash-on-arrival as a payment option. | tenant-booking-web, consumer-mobile |
tenant.payment.sharia-compliant | boolean | false | Enable Sharia-compliant payment policy display (no interest, no conventional credit). | tenant-booking-web |
tenant.checkin-window.early-override-enabled | boolean | false | Allow front desk to check in guests before the configured window without supervisor approval. | operator-desktop |
tenant.housekeeping.ai-order-enabled | boolean | true | Enable AI-suggested housekeeping order. | operator-desktop |
tenant.notifications.push-enabled | boolean | true | Enable OS push notifications for operator desktop. | operator-desktop |
tenant.notifications.whatsapp-enabled | boolean | false | Enable WhatsApp channel for guest notifications. Requires WhatsApp Business API credentials. | — |
tenant.reporting.tax-report-auto-export | boolean | false | Automatically export monthly tax report at month-end. | operator-desktop |
tenant.theme.rtl-default | boolean | (from locale) | Force RTL layout regardless of browser locale. | all |
tenant.locale.numeral-variant | string | "latin" | "latin" or "locale". Controls whether body copy uses locale numerals. | all |
5. Dev / CI / testing flags
These are never surfaced in production. Set via .env.local or CI env vars.
| Flag key | Type | Default | Description |
|---|---|---|---|
NEXT_PUBLIC_FF_FORCE_OFFLINE | boolean | false | Force consumer web into offline/degraded mode. |
NEXT_PUBLIC_FF_SKIP_3DS | boolean | false | Skip 3DS challenge in booking funnel (test only). |
REACT_NATIVE_FF_MOCK_BLE | boolean | false | Mock BLE scanner for mobile key testing. |
ELECTRON_FF_MOCK_LOCK_VENDOR | boolean | false | Return mock success/fail from lock vendor adapter. |
ELECTRON_FF_FORCE_SYNC_CONFLICT | boolean | false | Inject a synthetic sync conflict on next pull. |
6. Hook usage
// Boolean flag
const showMap = useFeatureFlag("consumer-map-view");
// With tenant context (resolved server-side; do not call BFF from component)
const hasLoyaltyCode = useFeatureFlag("tenant.booking-flow.loyalty-code");
// Number flag
const holdTimeout = useFeatureFlagNumber("booking-hold-timeout-minutes");
The useFeatureFlag hook reads from the React Query cache populated at bootstrap. It does not make network calls during render.
7. Flag lifecycle
| Stage | Description |
|---|---|
| Draft | Flag defined here, not yet in codebase. |
| Active | Flag in codebase; defaultValue is the live production default. |
| Graduated | Feature permanently enabled; flag removed from code in the next release. |
| Retired | Feature permanently disabled; flag removed from code. |
Flag cleanup PRs are required within 2 releases of graduation or retirement.
8. Open Questions
- Should
opensearch-meta-searchhave a gradual rollout rate (e.g., 10% → 50% → 100%) rather than binary? Would require a number flag + per-session sampling. - How should tenant flags override platform flags when they conflict? Current: tenant flag wins unless marked
killSwitch: trueat platform level. - Add a
tenant.booking-flow.deposit-requiredflag for properties that require a deposit at booking time?
References
../common/06-theming-and-tenant-config.md§17 (tenant toggles)../common/02-architecture-overview-frontend.mdC1-telemetry-event-dictionary.md(telemetry sampling flags)