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)
| Metric | Target | Where it is gated |
|---|---|---|
| LCP (Largest Contentful Paint, p75) | < 2.5 s on Moto G4 / Slow 4G | Lighthouse-CI on PR |
| INP (Interaction to Next Paint, p75) | < 200 ms | RUM dashboard alarm |
| CLS (Cumulative Layout Shift, p75) | < 0.1 | Lighthouse-CI on PR |
| TTFB (Time to First Byte, p75) | < 600 ms | RUM dashboard |
| FID (legacy, where reported) | < 100 ms | RUM dashboard |
| Initial JS per route (gzipped) | < 250 KiB | @next/bundle-analyzer budget |
| Initial CSS (gzipped, incl. tenant theme) | < 30 KiB | budget gate |
| Web Font payload | <= 2 weights x 2 styles per locale; subsetting required | build-time check |
| Hydration mismatch (theme flicker) | 0 occurrences in production telemetry | RUM alarm; treat as P1 |
1.2 Mobile (Consumer Mobile, Staff Mobile Companion)
| Metric | Target | Where it is gated |
|---|---|---|
| Cold start (TTI) | < 3 s on Pixel 4a / Android 11 | Reassure benchmark |
| Warm start | < 1 s | Reassure |
| Screen transition | < 250 ms | Reassure + manual perf review |
| JS bundle (Android, Hermes-compiled) | < 6 MiB | EAS Build report |
| APK / IPA size | APK <= 35 MiB, IPA <= 50 MiB | EAS Build gate |
| Memory steady-state on Discover | < 220 MiB | Manual profiling pre-release |
| Crash-free sessions | >= 99.5% | Sentry release gate |
1.3 Desktop (Operator Desktop, Kiosk family)
| Metric | Target | Where it is gated |
|---|---|---|
| Cold start to first paint | < 1.5 s on i5-8265U / 8 GiB RAM | Manual perf gate per release |
| Warm start (returning user) | < 600 ms | Manual perf gate |
| Front-desk reservation list render (50 rows) | < 200 ms p95 | Synthetic perf test in CI |
| Sync round-trip (full pull on small property) | < 5 s | Manual perf gate |
| Local AI first-token (operator copilot, ONNX) | < 1.2 s p95 on M1 Mac / equivalent | Manual perf gate |
| Local AI first-token (CPU-only fallback) | < 4 s p95 | Manual perf gate |
| Memory steady-state | < 800 MiB on operator desktop with active HK board | Manual profiling pre-release |
| Renderer crash-free hours | >= 100 hours MTBF | Sentry + 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-controlsper pattern. - Keyboard navigation: every actionable element reachable in DOM order; visible focus rings via
--focus-ringtoken; skip-to-content link in every page header. - Screen reader labels: every icon-only button has an
aria-labelfromnext-intl; mobile usesaccessibilityLabel. 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-describedbyon the field; error summary at top of form on submit. - CI:
axe-coreruns 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-leftetc. 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 vianumeral_variant: "locale". Authoritative reference:06-theming-and-tenant-config.md§12. - Pseudo-locale CI:
en-XArendered 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,HttpOnlyfor all session cookies;Path=/apion tenant cookie to scope - CSRF:
X-Idempotency-Key(ULID) on every state-changing request;Origin/Referercheck 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);
dangerouslySetInnerHTMLrequires// security-reviewed:comment + reviewer initials - Signed BFF handoff: HMAC-signed tokens; replay-safe via single-use
consumedflag - 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);
returnpasses onlyredirectResulttoken - 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
| Metric | Target | Notes |
|---|---|---|
| Web app availability | 99.9% (per app, per region) | Synthetic check every 60 s |
| Mobile crash-free sessions | >= 99.5% | Sentry release gate |
| Desktop renderer MTBF | >= 100 hours | Crash reporter |
| Sync recovery after 24h offline | 100% data integrity, no conflicts lost | Integration test fixture |
| Booking funnel completion (no transient errors) | >= 98% from quote to confirmation | Funnel telemetry |
| Zero-downtime deploy | Web + mobile + desktop releases never break in-progress sessions | Versioned BFF + 1-release overlap |
6. Telemetry and observability obligations
Every new screen MUST emit:
- One
view.page(web) orview.screen(mobile/desktop) on mount withpath,tenantId?,propertyId? funnel.stepevents for any multi-step flow (each stepenterand one ofsuccess/abandon/error)error.surfacedfor 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
/manageexposes 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.