Skip to main content

09 — Frontend Non-Functional Requirements

Scope: The single source of truth for measurable frontend NFRs across every surface (web, mobile, desktop, kiosk, tablet). Other docs MUST link here, not duplicate numbers. Every NFR below is enforced in CI or by a release gate; a deliberate change requires an ADR and updated baseline in the PR.

Companions: ../catalogs/C1-telemetry-event-dictionary.md · 10-frontend-testing-strategy.md


1. Performance budgets

1.1 Web (Consumer Meta, Tenant Booking, Guest Portal, Control Plane, OTA Portal)

MetricTargetWhere it is gated
LCP (Largest Contentful Paint, p75)< 2.5 s on Moto G4 / Slow 4GLighthouse-CI on PR
INP (Interaction to Next Paint, p75)< 200 msRUM dashboard alarm
CLS (Cumulative Layout Shift, p75)< 0.1Lighthouse-CI on PR
TTFB (Time to First Byte, p75)< 600 msRUM dashboard
FID (legacy, where reported)< 100 msRUM dashboard
Initial JS per route (gzipped)< 250 KiB@next/bundle-analyzer budget
Initial CSS (gzipped, incl. tenant theme)< 30 KiBbudget gate
Web Font payload<= 2 weights x 2 styles per locale; subsetting requiredbuild-time check
Hydration mismatch (theme flicker)0 occurrences in production telemetryRUM alarm; treat as P1

1.2 Mobile (Consumer Mobile, Staff Mobile Companion)

MetricTargetWhere it is gated
Cold start (TTI)< 3 s on Pixel 4a / Android 11Reassure benchmark
Warm start< 1 sReassure
Screen transition< 250 msReassure + manual perf review
JS bundle (Android, Hermes-compiled)< 6 MiBEAS Build report
APK / IPA sizeAPK <= 35 MiB, IPA <= 50 MiBEAS Build gate
Memory steady-state on Discover< 220 MiBManual profiling pre-release
Crash-free sessions>= 99.5%Sentry release gate

1.3 Desktop (Operator Desktop, Kiosk family)

MetricTargetWhere it is gated
Cold start to first paint< 1.5 s on i5-8265U / 8 GiB RAMManual perf gate per release
Warm start (returning user)< 600 msManual perf gate
Front-desk reservation list render (50 rows)< 200 ms p95Synthetic perf test in CI
Sync round-trip (full pull on small property)< 5 sManual perf gate
Local AI first-token (operator copilot, ONNX)< 1.2 s p95 on M1 Mac / equivalentManual perf gate
Local AI first-token (CPU-only fallback)< 4 s p95Manual perf gate
Memory steady-state< 800 MiB on operator desktop with active HK boardManual profiling pre-release
Renderer crash-free hours>= 100 hours MTBFSentry + Electron crash reporter

Budget regressions block CI; a deliberate budget bump requires an ADR-lite note in the PR description and an updated baseline.


2. Accessibility

  • Target: WCAG 2.2 AA across every surface, audited per release.
  • Semantic HTML on web: <header>, <nav>, <main>, <form>, <button> (never <div onClick>); aria-current, aria-expanded, aria-controls per pattern.
  • Keyboard navigation: every actionable element reachable in DOM order; visible focus rings via --focus-ring token; skip-to-content link in every page header.
  • Screen reader labels: every icon-only button has an aria-label from next-intl; mobile uses accessibilityLabel. Critical flows tested with VoiceOver, TalkBack, and NVDA per release.
  • Focus management: modals trap focus; closing a modal returns focus to trigger; route changes move focus to page heading (<h1 tabIndex={-1}>).
  • Reduced motion: respect prefers-reduced-motion (web) / Reduce Motion (mobile); animations collapse to opacity fades.
  • High contrast: opt-in high-contrast theme variant (token-based; see 03-design-system.md).
  • Touch targets: minimum 44x44 pt mobile, 32x32 px web (per WCAG 2.5.5).
  • Form errors: aria-describedby on the field; error summary at top of form on submit.
  • CI: axe-core runs on every Storybook story (web) and on a Detox a11y pass (mobile); axe-results-zero is a release gate.

The full WCAG SC-by-surface matrix lands in 14-accessibility-matrix.md (Phase C).


3. Internationalisation and localisation

  • Locales (Phase 1): ps-AF (Pashto, RTL), fa-AF (Dari, RTL), fa-IR (Persian, RTL), ar-SA / ar-EG (Arabic, RTL), en-US (English, LTR), ur-PK (Urdu, RTL).
  • Locales (Phase 2): fr-FR (French, LTR).
  • ICU MessageFormat via next-intl (web/desktop) and @formatjs/intl (mobile bridge).
  • Direction injection at root: <html dir> web; I18nManager.forceRTL() mobile (toggle requires reload).
  • Logical CSS only in shared code; raw padding-left etc. lint-blocked.
  • Mirrored iconography per @ghasi/icons/manifest.json — chevrons / arrows / back / progress mirror; logos / brand / numerals / media controls do not.
  • Numerals (F4 — canonical rule): Latin numerals MUST be used for money, dates, IDs, quantities, and any financial or legal confirmation across all locales and all surfaces. This is a finance audit invariant enforced at the BFF serialization layer and in acceptance tests (numeral_type: "latin" assertion in every folio/receipt/confirmation test). Locale numerals (Persian-Indic: ۰۱۲۳..., Arabic-Indic: ٠١٢٣...) are permitted only in narrative body copy (room descriptions, blog content, messaging) when a tenant's locale-pack opts in via numeral_variant: "locale". Authoritative reference: 06-theming-and-tenant-config.md §12.
  • Pseudo-locale CI: en-XA rendered for every PR; truncation + RTL flips checked.

4. Security baseline (FE-side; full model in 07-security-compliance-tenancy.md)

  • CSP enforced per-route with nonces; default-src 'self'; image / script / connect allow-lists explicit per BFF host
  • Cookies: SameSite=Lax, Secure, HttpOnly for all session cookies; Path=/api on tenant cookie to scope
  • CSRF: X-Idempotency-Key (ULID) on every state-changing request; Origin / Referer check at BFF for unsafe methods
  • XSS: all content rendered via React's escaped slots; rich-content blocks sanitised at BFF (DOMPurify allow-list per kind); dangerouslySetInnerHTML requires // security-reviewed: comment + reviewer initials
  • Signed BFF handoff: HMAC-signed tokens; replay-safe via single-use consumed flag
  • Mobile secrets: JWT in iOS Keychain / Android Keystore; MMKV encrypted with key from secure store; biometric prompt re-auth before token release
  • Payment surfaces: SPA never sees PAN; redirects to provider hosted checkout (Adyen, PayPal); return passes only redirectResult token
  • Network pinning (mobile, Phase 2): SSL pinning to BFF cert chain
  • Telemetry endpoints: write-only and rate-limited per session; PII deny-list enforced client-side

5. Reliability

MetricTargetNotes
Web app availability99.9% (per app, per region)Synthetic check every 60 s
Mobile crash-free sessions>= 99.5%Sentry release gate
Desktop renderer MTBF>= 100 hoursCrash reporter
Sync recovery after 24h offline100% data integrity, no conflicts lostIntegration test fixture
Booking funnel completion (no transient errors)>= 98% from quote to confirmationFunnel telemetry
Zero-downtime deployWeb + mobile + desktop releases never break in-progress sessionsVersioned BFF + 1-release overlap

6. Telemetry and observability obligations

Every new screen MUST emit:

  • One view.page (web) or view.screen (mobile/desktop) on mount with path, tenantId?, propertyId?
  • funnel.step events for any multi-step flow (each step enter and one of success / abandon / error)
  • error.surfaced for every user-visible error (toast, banner, modal)
  • Web Vitals (web) / Reassure profile (mobile) / OTel span (desktop) for the screen render

Full event catalog: ../catalogs/C1-telemetry-event-dictionary.md (P1).


7. Capacity and scale

  • Search results: pagination capped at offset=1000; cursor-paged unavailable on cross-tenant ranking
  • Image gallery: max 60 images per property; lazy + virtualised
  • HK board: max 500 rooms per property in the in-memory model
  • Reservation list: virtualised at >50 rows; server-side filtering preferred
  • Map clustering: client-side above 50 pins

8. Compliance touchpoints (FE)

  • GDPR data-subject self-service: Guest Portal /manage exposes export + delete request flow (R2)
  • PCI: SPA never sees PAN; redirect-to-provider model only
  • AF / PK regulatory: passport / national-ID capture flow on registration card; immutable-ID on receipts
  • Audit log viewer: cross-tenant queries gated by super-admin role; every query is itself logged

9. Open questions

  • Do we ship a service-worker-backed offline write queue for the Guest Portal, or rely on connectivity-required UX? Affects the Guest Portal spec.
  • Mobile session-replay: Sentry session-replay vs FullStory vs none? PII redaction and AF/PK privacy law compliance both must be evaluated.
  • Web font subsetting per locale: do we ship combined Latin+Arabic+Devanagari subsets, or per-locale dynamic loads? Affects the 30 KiB CSS budget.

References