9.5 KiB
9.5 KiB
Frontend Technical Specs and Requirements (MVP)
Purpose
Define the implementation contract for the React frontend against the current backend REST API so the customer flows (auth, search, booking, payment, profile) can ship reliably for KSA.
Scope
In scope:
- Customer web app (React + Vite) for Phase 1 flows.
- API integration contracts for current backend endpoints.
- UX/error/loading behavior and test requirements.
- i18n/RTL and KSA timezone handling.
Out of scope (Phase 2+):
- Manager/staff admin dashboards.
- Advanced reporting/reviews moderation tools.
- Full observability product dashboards.
Product and Platform Constraints
- Market default: KSA first.
- Default locale:
ar-sa; fallback:en. - Timezone baseline:
Asia/Riyadh(+03:00). - API error contract: HTTP status +
detailwhere applicable. - Booking/payment operations must avoid duplicate side effects.
UX Priorities (Primary Contract)
- First screen for authenticated and guest users MUST be a feed of nearby/available salons.
- The feed is the default home experience and primary entry to booking.
- Main customer navigation MUST be bottom tabs (mobile-first), not header-first navigation.
- Bottom tabs MUST include at minimum:
- Home/Feed
- Bookings
- Profile
- Optional tabs (when implemented) may include Search/Explore and Payments, but must not displace Home/Feed as default.
Frontend Architecture Requirements
Runtime and Stack
- React 18 + Vite.
- React Router (
BrowserRouter) for route navigation. i18next+react-i18nextfor translations and direction switching.fetchwrapper insrc/api/client.jsas single API boundary.- Auth/session state in
AuthContext.
Route Map (Customer)
/home feed (nearby/available salons) + search/filter./salon/:idsalon detail./loginphone OTP login./book?salon=<id>booking creation./pay?booking=<id>payment initiation./pay/returnpayment callback/return surface./bookingscustomer booking history./profilecustomer profile summary.
Module Boundaries
src/api/: all HTTP logic, standardized errors.src/contexts/: auth/session lifecycle only.src/hooks/: domain-side UI logic (useSalonSearch,usePaymentForm).src/pages/: route-level composition.src/components/: reusable presentation and guarded wrappers.src/i18n/: locale dictionaries and locale/direction state.
Functional Requirements
FR-1 Phone-First Authentication
- Login MUST use:
POST /api/auth/phone/request/POST /api/auth/phone/verify/
- Password auth endpoint (
/api/auth/token/) MUST NOT be used (returns 410). - Login request form MUST collect:
phone_number(accept KSA local or E.164 input)channel(smsorwhatsapp)- optional:
device_id(recommended for abuse controls)
- Verify step MUST submit
request_id+ 6-digitcode. - On success, frontend MUST persist
accessandrefreshtokens and user payload.
FR-2 Session Restore and Token Refresh
- On app boot, if
accessexists:- call
GET /api/auth/me/.
- call
- If
401/token invalid:- call
POST /api/auth/token/refresh/once. - retry
GET /api/auth/me/with new access token.
- call
- If refresh fails, frontend MUST clear tokens and require re-login.
FR-3 Salon Discovery
- Home MUST render a salon feed by default on first load.
- Feed data MUST come from
GET /api/salons/and support query params for discovery. - Home search MUST call
GET /api/salons/?q=<query>. - Search SHOULD support additional filters when UI is added:
cityservice
- Nearby/available ranking can be client-side initially, but server response MUST remain source of truth.
- Result cards MUST link to
/salon/:id.
FR-4 Salon Detail
- Detail page MUST call
GET /api/salons/:id/. - UI MUST render:
- salon base info
- services (duration, amount, currency)
- staff list
- optional reviews/photos if present
- CTA MUST deep-link to booking flow with salon id.
FR-5 Booking Creation
- Booking page MUST require authenticated user.
- Create booking with
POST /api/bookings/using:servicestaff(required)start_timeend_time- optional
notes
end_timeMUST match service duration exactly.- Datetime submitted to backend MUST include explicit offset (
+03:00for KSA baseline). - On success (
201), frontend MUST navigate to payment flow with booking id.
FR-6 Booking History
/bookingsMUST call authenticatedGET /api/bookings/.- List MUST show booking id, status, salon/service labels, datetime, and price.
- Datetime rendering MUST use active locale formatting.
FR-7 Payment Initiation (Idempotent)
- Payment submission MUST call
POST /api/payments/. - Payload requirements:
booking_id(number)provider=moyasaridempotency_key(UUID)sourceobject with supported type (stcpay,token,applepay,samsungpay)callback_urlrequired forsource.type=token
- Frontend MUST disable duplicate submits while request is in-flight.
- Same payment attempt retry MUST reuse the same
idempotency_key. - New attempt MUST generate a new key.
- If response includes
redirect_url, frontend MUST redirect.
FR-8 Payment Return Handling
/pay/returnMUST parse query params:statusid
- Success statuses shown as success UX:
paid,captured,authorized. - Non-success statuses MUST show neutral/pending/failure guidance and link to profile/bookings.
FR-9 Locale and Direction
- App MUST allow switching between
ar-saanden. - Locale switch MUST:
- persist preference in local storage
- set
<html lang> - set
<html dir>(rtlforar-sa,ltrforen)
- API calls MUST include
Accept-Languageheader with active locale.
API Contract Requirements
| Endpoint | Auth | Request | Success | Error handling |
|---|---|---|---|---|
POST /api/auth/phone/request/ |
No | phone_number, channel, optional profile fields |
201 with request_id, expires_at |
429 may include retry_after_seconds; show wait message |
POST /api/auth/phone/verify/ |
No | request_id, code |
200 with access, refresh, user |
400 invalid/expired code |
POST /api/auth/token/refresh/ |
No | refresh |
200 with new access |
logout on failure |
GET /api/auth/me/ |
Bearer | - | 200 user payload |
401 triggers refresh flow |
GET /api/salons/ |
No | q, optional city, service |
200 list |
show localized generic fetch error |
GET /api/salons/:id/ |
No | - | 200 detail object |
show detail/fallback |
POST /api/bookings/ |
Bearer | booking payload | 201 booking |
400 field validation errors |
GET /api/bookings/ |
Bearer | - | 200 list |
auth + generic errors |
POST /api/payments/ |
Bearer | payment payload | 201 created or 200 reused idempotent record |
400/403 with details; never auto-retry with new key |
Error and State Handling Requirements
- API wrapper MUST throw structured errors with:
- HTTP status
- parsed response body
- best message (
detailfirst, fallback to response text)
- For validation objects (
{field: [msg]}), UI SHOULD render first field message near form and keep raw object in debug logs. - For
429withretry_after_seconds, UI MUST display server-provided cooldown. - All mutating forms MUST expose:
- idle/loading/error/success states
- submit button disabled while loading
Security and Abuse-Resistance Requirements
- Use Bearer access token for authenticated endpoints only.
- Include optional
device_idduring phone auth request to strengthen backend abuse controls. - Never send raw card PAN/CVV data to backend; use tokenized sources only.
- On logout, clear user and both tokens from memory + storage.
Accessibility and UX Requirements
- All interactive controls MUST have accessible labels.
- Auth/booking/payment forms MUST be keyboard usable.
- Error text MUST be visible and associated with active form context.
- Layout MUST remain usable on mobile widths (
>=320px) and desktop.
Non-Functional Requirements
- Reliability: no duplicate payment submission side effects for one attempt.
- Consistency: API errors surfaced predictably and localized where available.
- Maintainability: domain behavior in hooks/services, not route components.
- Extensibility: route/module structure must support manager/staff pages later without rewrite.
Test Requirements (Frontend)
- Test stack:
vitest+ Testing Library. - Required coverage for release:
- phone login request + verify success/failure + 429 cooldown message
- auth restore and refresh-token fallback
- protected route redirect behavior
- salon search loading/empty/results/error
- booking form validation + API error mapping + success redirect
- payment form source validation + idempotency key reuse on retry + redirect behavior
- locale switching persists and sets
lang/dir - bookings list rendering and localized datetime output
Run:
cd frontend && npm run test
Definition of Done (Frontend)
- All FR requirements implemented for in-scope routes.
- API integrations match endpoint/payload contract above.
- No use of deprecated password login API.
- All listed frontend tests pass.
ar-saandenUX verified on mobile + desktop.
Known Dependencies and Open Decisions
- OAuth/social-linking policy is not finalized; keep social login UI hidden for now.
- Cancellation and refund policies are not finalized; do not ship irreversible customer actions until policy finalization.
- Detailed business-hours/timezone policy beyond current backend validation remains open; keep KSA-offset submission and avoid client-side assumptions that override server validation.