Files
Salon/docs/frontend-spec-requirements.md

217 lines
9.5 KiB
Markdown

# 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 + `detail` where 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-i18next` for translations and direction switching.
- `fetch` wrapper in `src/api/client.js` as single API boundary.
- Auth/session state in `AuthContext`.
## Route Map (Customer)
- `/` home feed (nearby/available salons) + search/filter.
- `/salon/:id` salon detail.
- `/login` phone OTP login.
- `/book?salon=<id>` booking creation.
- `/pay?booking=<id>` payment initiation.
- `/pay/return` payment callback/return surface.
- `/bookings` customer booking history.
- `/profile` customer 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` (`sms` or `whatsapp`)
- optional: `device_id` (recommended for abuse controls)
- Verify step MUST submit `request_id` + 6-digit `code`.
- On success, frontend MUST persist `access` and `refresh` tokens and user payload.
### FR-2 Session Restore and Token Refresh
- On app boot, if `access` exists:
- call `GET /api/auth/me/`.
- If `401`/token invalid:
- call `POST /api/auth/token/refresh/` once.
- retry `GET /api/auth/me/` with new access token.
- 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:
- `city`
- `service`
- 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:
- `service`
- `staff` (required)
- `start_time`
- `end_time`
- optional `notes`
- `end_time` MUST match service duration exactly.
- Datetime submitted to backend MUST include explicit offset (`+03:00` for KSA baseline).
- On success (`201`), frontend MUST navigate to payment flow with booking id.
### FR-6 Booking History
- `/bookings` MUST call authenticated `GET /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` = `moyasar`
- `idempotency_key` (UUID)
- `source` object with supported type (`stcpay`, `token`, `applepay`, `samsungpay`)
- `callback_url` required for `source.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/return` MUST parse query params:
- `status`
- `id`
- 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-sa` and `en`.
- Locale switch MUST:
- persist preference in local storage
- set `<html lang>`
- set `<html dir>` (`rtl` for `ar-sa`, `ltr` for `en`)
- API calls MUST include `Accept-Language` header 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 (`detail` first, 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 `429` with `retry_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_id` during 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-sa` and `en` UX 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.