EP-021: Mobile Applications
Business Objective
Hotel operations are inherently mobile -- housekeeping staff move floor-to-floor, F&B servers work tableside, and managers walk the property. Desktop dashboards force these roles back to a workstation, creating delays. Purpose-built mobile apps put the right tools in each role's hands: housekeepers update room status in real-time (reducing "room ready" lag from 15 minutes to under 2 minutes), servers place orders tableside (eliminating handwritten KOTs), and managers approve exceptions (voids, rate overrides) without returning to the back office. Offline capability is critical -- Indian hotels frequently experience intermittent WiFi in basements, kitchens, and upper floors.
Audience
- Primary: Housekeeping Staff, F&B Staff/Servers, Hotel Managers
- Secondary: Front Desk Agents (notifications), Maintenance Staff (work orders), IT Admin (device management)
Scope
In Scope
- Housekeeping App: Task queue (assigned rooms for shift), room status update (swipe to change: dirty -> in-progress -> inspected -> clean), completion photos (before/after via camera), cleaning duration timer, configurable checklist per room type, minibar inventory count, maintenance request creation with photo, offline sync with conflict resolution
- F&B Service App: Table floor plan with status indicators, tableside ordering (tap table -> browse menu -> add items -> submit KOT), menu browser with search, category filters, and dietary tags, order management (modify items, void with reason code, split/merge checks), bill presentation to guest on device, room charge lookup and posting, shift open/close with cash drawer count
- Manager App: KPI dashboard (today's occupancy, ADR, RevPAR, F&B revenue), approval queue (pending voids, discounts > 20%, rate overrides, late check-outs), alert center (open maintenance requests, guest complaints, system health), quick reports (daily revenue, housekeeping productivity, F&B covers)
- Cross-Cutting: Offline sync queue with retry and conflict resolution, push notifications via Expo Push Service, camera integration (ID scan, housekeeping photos, maintenance evidence), biometric login (fingerprint/Face ID via expo-local-authentication)
Out of Scope
- Guest-facing mobile app (covered by booking engine / future guest app epic)
- Tablet-optimized layouts (future consideration -- current focus is phone form factor)
- Wearable integrations (smartwatch notifications -- future)
- App Store / Play Store publishing process (separate release management epic)
Current Implementation Status
- Monorepo: Turborepo-managed monorepo at
04-hmp-mobile-apps/with shared packages (api-client, auth, shared-ui, utils). Expo SDK with file-based routing via expo-router. - Housekeeping App: Expo app with tab navigation (tasks, rooms, maintenance, profile). Auth flow with login screen. Task detail screen (
app/task/[id].tsx), room detail screen (app/room/[id].tsx). Components: RoomCard, RoomStatusSelector, TaskCard (with tests). E2e test directory with Detox configuration (.detoxrc.jsat monorepo root). - F&B App: Expo app with tab navigation (tables, orders, profile). Auth flow. Table detail screen (
app/table/[id].tsx), order detail screen (app/order/[id].tsx). Components: OrderCard, OrderEntry, TableFloorPlan (with tests). - Manager App: Expo app with tab navigation (dashboard, approvals, operations, reports, profile). Auth flow. Property detail screen (
app/property/[id].tsx), report detail screen (app/report/[id].tsx). Components: ApprovalCard, MetricCard (with tests). - Shared Packages:
api-client(HTTP client with auth interceptor),auth(token storage, refresh logic),shared-ui(common components),utils(formatters, validators). - Build Config: EAS Build configured per app (
eas.jsonin each app directory). Jest config for unit tests. Detox for e2e (housekeeping app).
Gap Analysis
- Offline Sync: The utils package has offline sync queue scaffolding, but conflict resolution (server wins vs. client wins vs. manual merge) is not implemented. When a housekeeper updates room status offline and another user updates the same room, the behavior is undefined.
- Camera/Photo Upload: Housekeeping app has camera access capability, but the photo upload pipeline (capture -> compress -> upload to S3 -> store URL in backend) is not connected. The backend housekeeping service does not have an endpoint for photo attachment.
- Manager Approval Workflow: The approvals tab and ApprovalCard component render mock data. The backend approval endpoints (void approval, discount approval, rate override approval) exist in the POS and reservation services but the mobile app is not connected to them.
- Push Notifications: Expo push token registration is not implemented. The notification service in the backend can send emails but does not support push notification delivery via Expo Push Service.
- Biometric Login: Not implemented. The auth package uses email/password only.
expo-local-authenticationis not installed. - F&B POS Integration: Table floor plan and order screens exist with mock data. The actual integration with the POS service (menu fetch, order create, payment post) is not wired. KOT submission to KDS via Socket.io/Kafka is not connected.
- Room Charge Posting: F&B app has no integration with the folio/billing system to post F&B charges to a guest's room.
- Shift Management: Neither the F&B app nor the housekeeping app implements shift open/close workflows.
- App Store Publishing: EAS Build is configured but no app signing certificates, store listings, or review submissions have been prepared.
User Stories
| Story ID | Title | Priority | Points | Status | Sprint |
|---|---|---|---|---|---|
| US-021-001 | Housekeeping Task Queue & Room Status Update | P0 | 8 | Partial | 5 |
| US-021-002 | Housekeeping Photo Capture & Upload | P1 | 5 | Partial | 6 |
| US-021-003 | Housekeeping Checklist & Minibar Count | P1 | 5 | Not Started | 7 |
| US-021-004 | F&B Tableside Ordering | P0 | 8 | Partial | 5 |
| US-021-005 | F&B Menu Browser with Search & Filters | P0 | 5 | Partial | 5 |
| US-021-006 | F&B Order Management (Modify, Void, Split) | P1 | 8 | Not Started | 7 |
| US-021-007 | F&B Room Charge Posting | P1 | 5 | Not Started | 8 |
| US-021-008 | Manager KPI Dashboard | P0 | 5 | Partial | 5 |
| US-021-009 | Manager Approval Queue | P0 | 8 | Partial | 6 |
| US-021-010 | Cross-App Offline Sync with Conflict Resolution | P0 | 8 | Partial | 6 |
| US-021-011 | Push Notifications via Expo Push Service | P1 | 5 | Not Started | 7 |
| US-021-012 | Biometric Login (Fingerprint / Face ID) | P2 | 3 | Not Started | 9 |
| US-021-013 | Shift Management (Open/Close) | P2 | 5 | Not Started | 9 |
Dependencies
- EP-001 (Auth & Access): Mobile auth uses JWT tokens from the auth service; biometric login stores tokens locally
- EP-005 (Housekeeping): Backend housekeeping service APIs for task assignment, room status, checklist
- EP-008 (POS & F&B): POS service APIs for menu, orders, payments, void/discount approval
- EP-010 (Billing & Folio): Folio service API for room charge posting
- EP-015 (Notifications): Notification service must support Expo push token registration and delivery
- EP-020 (Infrastructure): S3 bucket for photo uploads, CDN for image delivery
Acceptance Criteria (Epic Level)
- All three apps install and run on iOS 16+ and Android 13+ devices
- Housekeeping staff can view assigned tasks, update room status, and see changes reflected on the dashboard within 5 seconds
- F&B staff can browse the menu, place an order, and the KOT appears on the KDS within 3 seconds
- Managers can approve/reject pending items from the approval queue on their phone
- All apps function in offline mode for core operations (status updates, order drafts) and sync when connectivity resumes
- Push notifications deliver to the correct user within 10 seconds of the triggering event
- App launch to interactive state in under 3 seconds on mid-range Android devices
KPIs / Success Metrics
- Housekeeping room status update lag: < 2 minutes (from physical completion to system update)
- F&B order-to-KDS delivery time: < 3 seconds
- Manager approval response time: < 5 minutes (median, during working hours)
- Offline sync success rate: > 99.5% (operations queued offline successfully synced)
- App crash rate: < 1% of sessions
- Daily active usage: > 80% of staff in target roles
- Push notification delivery rate: > 95%
Detailed User Stories
US-021-001: Housekeeping Task Queue & Room Status Update
As a housekeeping staff member, I want to see my assigned rooms for today's shift and update each room's status with a swipe, So that front desk knows in real-time which rooms are ready for check-in.
Priority: P0 | Points: 8 | Sprint: 5 | Status: Partial
Implementation Status
The housekeeping app has tab navigation with a "Tasks" screen showing a list view and a "Rooms" screen. TaskCard and RoomCard components render room number, type, and current status. RoomStatusSelector component allows status selection. Task detail screen (app/task/[id].tsx) and room detail screen (app/room/[id].tsx) exist. However, the API integration is using mock data -- the api-client package has the HTTP client but the housekeeping service endpoints (GET /tasks, PATCH /rooms/:id/status) are not wired to the screens. The swipe-to-change-status gesture is not implemented (current UI uses a dropdown selector).
Acceptance Criteria
Scenario: Housekeeper views today's assigned rooms
Given the housekeeper "Priya" is logged in and assigned to Floor 3
When she opens the Tasks tab
Then she sees a list of rooms assigned to her shift, ordered by priority (checkout rooms first, then stayover)
And each card shows room number, room type, current status (dirty/in-progress/clean), and guest checkout time if applicable
And the list refreshes via pull-to-refresh
Scenario: Housekeeper updates room status via swipe
Given Room 301 is currently in "Dirty" status
When Priya swipes the room card to the right
Then the status changes to "In Progress" with a visual transition animation
And a PATCH request is sent to the backend: PATCH /api/v1/housekeeping/rooms/301/status { "status": "IN_PROGRESS" }
And the front desk dashboard reflects the status change within 5 seconds
Scenario: Status update works offline and syncs later
Given Priya's device loses WiFi connectivity while on Floor 3
When she swipes Room 302 from "In Progress" to "Inspected"
Then the status change is saved locally with a pending sync indicator (orange dot)
And when WiFi reconnects, the change syncs automatically
And if the room was updated by someone else in the meantime, the most recent timestamp wins
US-021-002: Housekeeping Photo Capture & Upload
As a housekeeping staff member, I want to take before/after photos of each room I clean, So that supervisors can verify quality without physically inspecting every room.
Priority: P1 | Points: 5 | Sprint: 6 | Status: Partial
Implementation Status
The Expo camera permission is configured in app.json. The room detail screen has a placeholder for photo capture. However, the end-to-end pipeline is incomplete: no camera component in the screen, no image compression utility, no upload to S3 (presigned URL flow), and the backend housekeeping service does not have a photo attachment endpoint. The S3 bucket for uploads is defined in the Terraform storage module but the presigned URL generation is not in the API gateway.
Acceptance Criteria
Scenario: Housekeeper takes a before photo when starting a room
Given Priya opens Room 305 detail screen and taps "Start Cleaning"
When the app prompts for a "Before" photo and she taps the camera button
Then the device camera opens in the app
And after capturing the photo, a compressed version (< 500 KB, 1280px max dimension) is saved locally
And the photo is displayed as a thumbnail on the room detail screen with label "Before"
Scenario: Photos upload to cloud storage with room association
Given Priya has taken before and after photos for Room 305
And the device has internet connectivity
When the upload process runs (automatically or on sync)
Then each photo is uploaded to S3 via a presigned URL obtained from the API
And the photo URLs are associated with the housekeeping task record in the database
And the supervisor can view the photos from the dashboard housekeeping module
Scenario: Photos are queued for upload when offline
Given Priya takes photos while offline in the basement floor
When she captures 3 room photos without connectivity
Then the photos are stored locally on-device with metadata (room number, type: before/after, timestamp)
And when connectivity resumes, all 3 photos upload automatically in sequence
And upload progress is shown in the app's sync status indicator
US-021-003: Housekeeping Checklist & Minibar Count
As a housekeeping supervisor, I want to define cleaning checklists per room type and have staff report minibar consumption, So that cleaning quality is standardized and minibar charges are posted to the guest folio accurately.
Priority: P1 | Points: 5 | Sprint: 7 | Status: Not Started
Implementation Status
Neither the mobile app nor the backend housekeeping service has checklist or minibar functionality. The room type configuration in the property service does not include checklist templates. This is a greenfield feature requiring backend schema changes (checklist_template, checklist_item, minibar_count tables), API endpoints, and mobile UI.
Acceptance Criteria
Scenario: Housekeeper follows room-type-specific checklist
Given Room 401 is a "Deluxe Suite" with a 12-item checklist (bed making, bathroom scrub, minibar restock, etc.)
When Priya opens Room 401 and starts cleaning
Then the checklist loads with all 12 items, each with a checkbox
And she must check off all mandatory items before she can mark the room as "Clean"
And optional items (e.g., "deep carpet clean") are marked with a different indicator
Scenario: Minibar consumption is recorded and posted to folio
Given Room 401 has a stayover guest and the minibar standard stock is defined (4 water, 2 cola, 2 beer, 1 wine)
When Priya counts the current minibar and enters: 3 water, 1 cola, 2 beer, 1 wine
Then the app calculates consumed items: 1 water, 1 cola
And the consumption is sent to the backend
And the billing service posts the minibar charge (water INR 50 + cola INR 80 = INR 130) to the guest's folio
Scenario: Incomplete checklist blocks room completion
Given Priya has completed 10 of 12 mandatory checklist items for Room 401
When she attempts to mark the room as "Clean"
Then the app prevents the status change and highlights the 2 incomplete items
And a message displays: "Complete all mandatory items before marking as Clean"
US-021-004: F&B Tableside Ordering
As an F&B server, I want to take orders directly at the guest's table using my phone, So that orders reach the kitchen faster and I avoid handwriting errors on paper KOTs.
Priority: P0 | Points: 8 | Sprint: 5 | Status: Partial
Implementation Status
The F&B app has a Tables tab with a TableFloorPlan component showing table layout, and an Orders tab listing active orders. The table detail screen (app/table/[id].tsx) and order detail screen (app/order/[id].tsx) exist. OrderEntry and OrderCard components have unit tests. However, all data is mocked. The POS service menu endpoints (GET /menu/categories, GET /menu/items) are not called. Order creation (POST /orders) is not wired. KOT submission to KDS via Kafka/Socket.io is not connected. The menu does not support modifiers (e.g., "no onion", "extra cheese").
Acceptance Criteria
Scenario: Server places a new order from a table
Given server "Rahul" taps on Table 5 (4 guests seated) from the floor plan
When he taps "New Order" and adds items: 2x Butter Chicken, 1x Dal Makhani, 4x Naan
Then each item appears in the order summary with quantity, price, and subtotal
And he can add modifiers to items (e.g., "Butter Chicken - extra spicy")
And when he taps "Send to Kitchen", a KOT is created via POST /api/v1/pos/orders
And the KOT appears on the KDS within 3 seconds
Scenario: Server adds items to an existing open order
Given Table 5 has an existing open order with 3 items
When Rahul taps Table 5 and selects the open order
Then he sees the current items and can tap "Add Items"
And new items are appended to the order as a separate KOT (KOT #2)
And the KDS displays the new KOT with a reference to the original order
Scenario: Order total includes GST and service charge
Given the order for Table 5 totals INR 1,200 in food items
When Rahul views the order summary
Then GST (5% for food) is calculated as INR 60
And service charge (10%) is calculated as INR 120
And the grand total displays as INR 1,380
US-021-005: F&B Menu Browser with Search & Filters
As an F&B server, I want to quickly find menu items by name, category, or dietary tag, So that I can answer guest questions and place orders efficiently during peak service.
Priority: P0 | Points: 5 | Sprint: 5 | Status: Partial
Implementation Status
The F&B app has an order entry screen with a basic list of items. No search bar, no category filter tabs, no dietary tags. The POS service has menu endpoints with category hierarchy, but the mobile app does not consume them. Menu data is hardcoded in the component. No local caching of the menu for fast browsing.
Acceptance Criteria
Scenario: Server searches for a menu item by name
Given Rahul is on the order entry screen for Table 5
When he types "paneer" in the search bar
Then the menu filters to show all items containing "paneer" (Paneer Tikka, Paneer Butter Masala, Palak Paneer)
And results appear within 200ms (from locally cached menu data)
And each result shows item name, price, and availability status
Scenario: Server filters by category and dietary tag
Given the restaurant menu has categories: Starters, Main Course, Desserts, Beverages
When Rahul taps "Main Course" and then filters by "Vegetarian"
Then only vegetarian main course items are displayed
And items marked as "Chef's Special" show a star indicator
And out-of-stock items appear greyed out at the bottom with "Unavailable" label
Scenario: Menu syncs on app launch and caches locally
Given the menu was last synced 2 hours ago
When Rahul opens the F&B app at the start of his shift
Then the app fetches the latest menu from GET /api/v1/pos/menu
And the menu is cached locally for offline/fast access
And if a menu item was added or price changed since last sync, the update is reflected
US-021-006: F&B Order Management (Modify, Void, Split)
As an F&B server or manager, I want to modify an order (change quantity, void an item with reason, split the check), So that I can handle guest requests and corrections without starting a new order.
Priority: P1 | Points: 8 | Sprint: 7 | Status: Not Started
Implementation Status
The order detail screen exists but only displays static order data. No modify, void, or split functionality is implemented in the mobile app. The POS service has endpoints for void (with reason code and manager approval) and order modification, but the mobile app does not call them. Check splitting logic does not exist in the frontend or backend.
Acceptance Criteria
Scenario: Server voids an item with reason code
Given Table 5 has an open order with "1x Chicken Biryani" that the guest wants removed
When Rahul selects the item and taps "Void"
Then a reason code picker appears (Guest Changed Mind, Wrong Item, Quality Issue, Other)
And Rahul selects "Guest Changed Mind" and confirms
And if the item value exceeds INR 500, the void is queued for manager approval
And once approved, the item is struck through on the order with the void reason displayed
Scenario: Server splits a check between two guests
Given Table 8 has an order with 6 items totaling INR 3,600
When Rahul taps "Split Check" and assigns items to Guest A (3 items, INR 2,000) and Guest B (3 items, INR 1,600)
Then two separate bills are generated, each with their own GST and service charge calculation
And each bill can be paid independently (cash, card, UPI, or room charge)
And the original order record maintains a reference to both split bills
Scenario: Manager approves a high-value void from the Manager App
Given Rahul voided a "Lobster Thermidor" (INR 2,500) pending manager approval
When Manager "Anil" opens the Manager App approvals tab
Then he sees the pending void with item details, table number, server name, and reason code
And he can approve or reject with an optional note
And once approved, the void is applied and Rahul's app shows a push notification: "Void approved for Table 5"
US-021-007: F&B Room Charge Posting
As an F&B server, I want to charge a restaurant bill to a guest's room, So that in-house guests can enjoy the convenience of a single folio at checkout.
Priority: P1 | Points: 5 | Sprint: 8 | Status: Not Started
Implementation Status
No room charge functionality exists in the F&B app. The folio/billing service in the backend supports posting charges by category, but the F&B mobile app has no integration with it. Room number lookup and guest verification (matching name/room) are not implemented.
Acceptance Criteria
Scenario: Server posts F&B bill to guest room
Given the bill for Table 3 is INR 2,400 and the guest requests room charge
When Rahul taps "Room Charge" and enters room number "504"
Then the app looks up Room 504 and displays the guest name (e.g., "Mr. Sharma, checked in 2 nights")
And Rahul confirms the guest name matches
And the charge is posted to Room 504's folio under the "F&B - Restaurant" category
And a receipt is shown on the app: "INR 2,400 charged to Room 504 - Mr. Sharma"
Scenario: Room charge rejected for vacant room
Given Room 220 is currently vacant (no active check-in)
When Rahul attempts to post a charge to Room 220
Then the app displays an error: "Room 220 is not currently occupied. Cannot post room charge."
And suggests alternative payment methods (cash, card, UPI)
Scenario: Room charge requires guest signature on device
Given the hotel policy requires guest signature for room charges above INR 1,000
When the charge amount is INR 2,400
Then the app presents a signature capture screen
And the guest signs on the device screen
And the signature image is attached to the folio entry as proof of authorization
US-021-008: Manager KPI Dashboard
As a hotel manager, I want to see today's key performance indicators on my phone, So that I can make informed decisions while walking the property without returning to my desk.
Priority: P0 | Points: 5 | Sprint: 5 | Status: Partial
Implementation Status
The Manager app has a Dashboard tab with MetricCard components displaying mock KPI data. The layout shows 4 metric tiles. The component has unit tests. However, the dashboard does not fetch real data from the analytics service. The analytics service aggregation endpoints (daily occupancy, ADR, RevPAR, revenue breakdown) exist but the mobile app uses hardcoded values. No pull-to-refresh. No date selector for historical comparison.
Acceptance Criteria
Scenario: Manager views today's KPIs on app launch
Given Manager "Anil" opens the Manager App
When the Dashboard tab loads
Then he sees real-time metrics: Occupancy (e.g., 78%), ADR (e.g., INR 5,200), RevPAR (e.g., INR 4,056), F&B Revenue (e.g., INR 1,24,000)
And each metric shows a comparison to yesterday (green arrow up or red arrow down with percentage change)
And the data is fetched from GET /api/v1/analytics/dashboard/today
Scenario: Manager views weekly trend
Given Anil taps on the "Occupancy" metric card
When the detail view opens
Then a 7-day trend chart is displayed showing daily occupancy percentage
And the chart highlights weekends (Saturday/Sunday) with a different color
And the average for the period is shown below the chart
Scenario: Dashboard data refreshes automatically
Given Anil keeps the Dashboard tab open
When 60 seconds pass
Then the KPI data auto-refreshes without user interaction
And if a metric changed since last refresh, the card briefly highlights to draw attention
And if the device is offline, the last-fetched data is displayed with a "Last updated: X min ago" label
US-021-009: Manager Approval Queue
As a hotel manager, I want to approve or reject pending operational requests (voids, discounts, rate overrides) from my phone, So that operations are not blocked waiting for me to return to the front desk.
Priority: P0 | Points: 8 | Sprint: 6 | Status: Partial
Implementation Status
The Manager app has an Approvals tab with ApprovalCard components. The component renders mock approval items with approve/reject buttons and has unit tests. The backend POS service has void approval endpoints, and the reservation service has rate override endpoints. However, the mobile app does not fetch pending approvals from the backend. The approve/reject actions are not wired. Push notifications for new approval requests are not implemented.
Acceptance Criteria
Scenario: Manager sees pending approvals sorted by urgency
Given there are 3 pending approvals: a void (10 min old), a discount request (2 min old), and a rate override (30 min old)
When Anil opens the Approvals tab
Then the approvals are sorted by age (oldest first: rate override, void, discount)
And each card shows: type, amount, requester name, reason, and time elapsed
And approvals older than 15 minutes are highlighted in amber as "urgent"
Scenario: Manager approves a discount request
Given Front Desk Agent "Meera" requested a 25% discount on Room 601 (corporate negotiated rate not in system)
When Anil reviews the request and taps "Approve" with note "Verified corporate agreement"
Then the approval is sent to the backend: POST /api/v1/reservations/rate-overrides/:id/approve
And Meera receives a push notification: "Discount approved by Anil for Room 601"
And the reservation rate is updated immediately
And the approval card moves to the "Completed" section with a green checkmark
Scenario: Manager rejects a void with reason
Given a server requested a void for "2x Whiskey Sour" (INR 1,200) with reason "Guest complaint"
When Anil taps "Reject" and enters reason: "No quality issue reported. Discuss with supervisor."
Then the rejection is sent to the backend
And the server receives a push notification with the rejection reason
And the void remains on the order and the amount stays on the guest bill
US-021-010: Cross-App Offline Sync with Conflict Resolution
As a mobile app user, I want to continue working when WiFi drops and have my changes sync automatically when connectivity resumes, So that I am never blocked from doing my job due to network issues.
Priority: P0 | Points: 8 | Sprint: 6 | Status: Partial
Implementation Status
The utils shared package has offline sync queue scaffolding with an async storage-based queue. Operations are enqueued with metadata (timestamp, endpoint, payload). However, conflict resolution is not implemented -- if two users modify the same resource offline, the last sync wins without warning. Retry logic with exponential backoff is not built. Queue persistence across app restarts is not tested. No UI indicator for pending sync items.
Acceptance Criteria
Scenario: Room status update queued offline and synced on reconnect
Given the housekeeping app loses connectivity
When Priya updates Room 310 from "Dirty" to "In Progress" and Room 311 from "Dirty" to "In Progress"
Then both updates are stored in the local sync queue with timestamps
And the app shows an orange banner: "2 changes pending sync"
And when WiFi reconnects, the updates are sent to the backend in order
And the banner clears with a brief "Synced" confirmation
Scenario: Conflict resolution when two users update the same room
Given Priya (offline) marks Room 315 as "Clean" at 10:05 AM
And Supervisor Deepa (online) marks Room 315 as "Needs Re-clean" at 10:07 AM via dashboard
When Priya's device reconnects and attempts to sync at 10:10 AM
Then the sync detects a conflict (server version is newer: "Needs Re-clean" at 10:07 vs. Priya's "Clean" at 10:05)
And the server version wins (timestamp-based resolution)
And Priya's app updates to show "Needs Re-clean" with a notification: "Room 315 status was updated by Deepa"
Scenario: Failed sync retries with exponential backoff
Given Priya's device reconnects but the backend is temporarily returning 503
When the sync queue attempts to send the first pending operation
Then the first retry happens after 2 seconds, then 4 seconds, then 8 seconds (exponential backoff)
And after 5 failed retries, the operation is marked as "Failed" in the queue
And Priya sees a "Sync failed - tap to retry" indicator on the affected items
US-021-011: Push Notifications via Expo Push Service
As a hotel staff member, I want to receive push notifications for events relevant to my role, So that I can respond promptly without constantly checking the app.
Priority: P1 | Points: 5 | Sprint: 7 | Status: Not Started
Implementation Status
Expo Push Notifications SDK is available in the Expo ecosystem but not installed or configured. The backend notification service handles email notifications but has no push notification channel. No Expo push token registration endpoint exists. No notification preferences or role-based routing logic.
Acceptance Criteria
Scenario: Push token registered on app login
Given the Housekeeping app requests notification permissions on first login
When Priya grants permission and the app obtains an Expo push token
Then the token is sent to the backend: POST /api/v1/notifications/push-tokens { token, userId, deviceId, platform }
And the token is stored in the user's device registry
And if Priya logs in on a second device, both tokens are registered
Scenario: Housekeeper receives push for new room assignment
Given Priya has the housekeeping app installed with push notifications enabled
When the supervisor assigns Room 405 to Priya via the dashboard
Then the backend publishes a Kafka event "housekeeping.task.assigned"
And the notification service consumes the event and sends an Expo push notification
And Priya's phone displays: "New Task: Room 405 (Checkout Clean) assigned to you"
And tapping the notification opens the task detail screen for Room 405
Scenario: Manager receives push for pending approval
Given Manager Anil has the Manager app with push notifications enabled
When a void request exceeding INR 500 is submitted by a server
Then Anil receives a push notification: "Approval Needed: Void INR 1,200 - Table 5 (Guest complaint)"
And the notification badge count increments on the Manager app icon
And tapping the notification opens the Approvals tab with the specific request highlighted
US-021-012: Biometric Login (Fingerprint / Face ID)
As a hotel staff member, I want to log into the mobile app using my fingerprint or Face ID, So that I can access the app quickly between tasks without typing my password each time.
Priority: P2 | Points: 3 | Sprint: 9 | Status: Not Started
Implementation Status
Not implemented. The auth package uses email/password login only. expo-local-authentication is not installed. No secure token storage with biometric guard (e.g., Expo SecureStore with biometric access control).
Acceptance Criteria
Scenario: Staff enables biometric login after initial password login
Given Priya has logged in with email/password and her device supports fingerprint
When she navigates to Profile > Security and toggles "Enable Biometric Login"
Then the app prompts for fingerprint authentication to confirm
And the current refresh token is stored in SecureStore with biometric access control flag
And subsequent app launches offer "Login with Fingerprint" as the primary option
Scenario: Biometric login on app resume
Given Priya has biometric login enabled and the app was backgrounded for 5 minutes
When she brings the app to the foreground
Then the app shows a biometric prompt (fingerprint or Face ID depending on device)
And upon successful biometric verification, the stored token is used to resume the session
And if the token has expired, a silent refresh is attempted before falling back to password login
Scenario: Biometric fallback to password
Given Priya's fingerprint fails 3 times (e.g., wet hands in housekeeping)
When the third biometric attempt fails
Then the app falls back to the email/password login screen
And a message displays: "Biometric login failed. Please enter your password."
US-021-013: Shift Management (Open/Close)
As an F&B server or housekeeping staff, I want to open and close my shift on the mobile app, So that management can track staffing hours and I can reconcile my cash drawer (F&B).
Priority: P2 | Points: 5 | Sprint: 9 | Status: Not Started
Implementation Status
No shift management functionality exists in any mobile app or backend service. The concept of "shift" (start time, end time, assigned area/station, cash float) is not modeled in the database schema. This is a greenfield feature.
Acceptance Criteria
Scenario: F&B server opens a shift with cash float
Given Rahul logs into the F&B app at the start of his evening shift
When he taps "Start Shift" and enters his opening cash float amount (INR 5,000)
Then a shift record is created: POST /api/v1/pos/shifts { userId, openFloat: 5000, station: "Restaurant A" }
And the app displays "Shift Active" with start time and assigned station
And all orders placed by Rahul during this shift are linked to the shift record
Scenario: F&B server closes shift with cash reconciliation
Given Rahul has been on shift for 8 hours with total cash collections of INR 12,500
When he taps "End Shift" and enters closing cash count (INR 17,300)
Then the app calculates: opening float (5,000) + cash collections (12,500) = expected (17,500)
And displays the variance: actual (17,300) - expected (17,500) = -200 (short by INR 200)
And Rahul must enter a reason for the variance before completing the shift close
And the shift summary is saved and visible to the manager in the reports section
Scenario: Housekeeping staff shift summary shows productivity
Given Priya closes her housekeeping shift after 8 hours
When the shift summary screen appears
Then it displays: rooms cleaned (14), average time per room (28 min), rooms with re-clean requests (1)
And the summary is sent to the housekeeping supervisor dashboard