Cross-role mobile features (apps/mobile) that apply regardless of which identity is active — guest gating, chat, search, listings, identity switching, payments, layout, and the App Store demo account. Includes the confirmed reason Company/Office roles are currently unreachable.
Company/Office accounts are entirely gated behind a 'Coming Soon' screen — confirmed intentional
P0
Confirm that Company and Office account types are deliberately locked app-wide — apps/mobile/src/app/(auth)/business-auth.tsx checks `const COMPANY_OFFICE_LOCKED = true;` and renders <ComingSoonGate /> instead of the real signup/login form, and both (company)/_layout.tsx and (office)/_layout.tsx short-circuit their entire tab navigators to that same gate — so that this documented, intentional kill-switch is treated as a release-readiness checkpoint to re-verify every release, not something QA needs to rediscover or escalate as a bug each pass.
AC-01COMPANY_OFFICE_LOCKED is true in the current build, and every entry point into company/office (the business-auth screen, the (company) tab group, the (office) tab group) shows the same 'قريباً' ComingSoonGate bottom sheet — non-dismissible, with only a 'العودة للرئيسية' way out.
AC-02'العودة للرئيسية' correctly returns the user to an individual identity if one exists on the account, or logs out to individual-auth if not — it never leaves the user stuck on a dead screen.
AC-03This flag's state is an explicit, called-out line item in every release QA sign-off — before shipping, confirm whether it's intentionally still true or whether product has asked for it to flip to false.
AC-04If/when this flips to false, every story in the Mobile — Company and Mobile — Office sections needs a full re-pass, since none of that functionality has been exercised by real users while the gate has been up.
Test Scenarios
TC-01Attempt to reach Office or Company signup from every entry point you can find (the selection screen doesn't offer them at all — see the Mobile — Individual section; also try deep-linking directly to /(auth)/business-auth?type=office) and confirm ComingSoonGate always appears, with no path reaching a real form.
TC-02Log in as an existing company/office test account (if one exists in the DB from before the lock) and confirm the (company)/(office) tab navigator is also gated — not just the auth screens.
TC-03Tap 'العودة للرئيسية' from the gate as a user with an individual identity available, and confirm it switches to that identity correctly; repeat as a user with no individual identity and confirm it logs out cleanly to individual-auth.
TC-04Before each release, explicitly re-check this flag's value in the shipped build (not just in the repo) since a build/env mismatch here would silently ship two completely unqualified onboarding paths to real users.
Guest action-gating shows the auth sheet, never a dead end
P0
Verify that every guarded action (Chat, Favorites, Notifications, Add Ad, Add Alert, Ask for Offer, Write Review) opens the Authentication Bottom Sheet for guest users, so that guests are always offered a clear path to sign up or log in instead of hitting a silent failure or crash.
AC-03Dismissing via 'لاحقاً' returns the guest to the exact screen/state they were on.
AC-04The same actions work immediately (no sheet) once a real session exists.
Test Scenarios
TC-01As a guest, tap the heart icon on a property card in Search results, Property Detail, and Home feed — confirm the sheet appears in all three places, not just one.
TC-02As a guest, tap the '+' add-listing button and the 'Ask for Offer' button on a property — confirm both are gated.
TC-03Complete login from the sheet mid-flow (e.g. from Favorites) and confirm the originally-attempted action completes automatically or the user lands back where they intended.
TC-04Kill and relaunch the app as a guest — confirm gating still triggers after a cold start (not just first-session state).
Verify the Socket.IO-backed chat (join_conversation/leave_conversation/send_message events, new_message/conversation_updated broadcasts) delivers messages reliably, so that buyers and sellers can trust conversations aren't dropped or duplicated. This applies identically to Individual chat and to company-chats/office-chats once the account-type gate lifts (mobile-company-office-gate) — all three screens share the same useChatStore.
AC-01Sending a message from device A appears on device B (same account, two sessions) within a few seconds without manual refresh.
AC-02conversation_updated correctly reorders/updates the chat list's last-message preview and unread badge.
AC-03Reopening the app after being offline reconnects the socket and catches up on missed messages via GET conversations/:id/messages.
AC-04POST conversations/:id/read clears the unread badge for that conversation only.
Test Scenarios
TC-01Two test accounts message each other; confirm delivery order matches send order on both ends.
TC-02Put device A in airplane mode mid-conversation, send messages from B, then bring A back online — confirm A receives the backlog.
TC-03Start a conversation from a Property Detail 'Chat' button as a guest — confirm this is gated by the auth sheet (see mobile-guest-guard), not a broken chat screen.
TC-04KNOWN STUB: attempt 'Attach image' and image download in a chat thread — these currently only console.log and do nothing visible. Confirm the buttons at least fail silently/gracefully rather than crashing, and file this as a known gap rather than a new bug.
Search suggestions are live; recent-search history is mock-only
P1
Verify that Search's live suggestions (real searchService calls) work correctly while confirming the 'recent searches' list is currently a mock/local array — so the mock history doesn't get misreported as a persistence bug, and gets tracked instead as a known gap (no Zustand/AsyncStorage persistence yet).
AC-01Typing a query in Search shows live suggestions sourced from the backend, updating as the user types (debounced, no stale results flashing in).
AC-02The GlobalFilterSheet filters (opened from Search) correctly narrow /search/results by tab and filters params.
AC-03'Recent searches' shown on the Search screen do NOT persist across app restarts (expected today) — confirm this matches the known mock behavior rather than treating it as a regression.
AC-04Search Results screen correctly reflects the tab/filters passed in via navigation params.
Test Scenarios
TC-01Type a partial property title/location and confirm suggestions load, then clear the field and confirm suggestions clear too.
TC-02Apply 2-3 filters in GlobalFilterSheet, submit, and confirm the results screen URL/params and rendered results match the selected filters.
TC-03Perform a search, force-quit the app, relaunch, and confirm 'recent searches' resets — document as expected (mock-only) rather than filing as a bug.
TC-04Search with no matching results and confirm a proper empty state renders (not a blank screen or infinite spinner).
Multi-tab listing creation (Sell/Rent/Exchange) saves consistent data
P0
Verify the add-listing flow (SharedPropertyInfo + SellPropertyTab/RentPropertyTab/ExchangePropertyTab, driven by useListingStore, with a Preview step) produces a correctly-typed property regardless of which tab the user starts from, so that listings don't get created with the wrong type or missing required fields.
AC-01Fields entered in SharedPropertyInfo persist correctly when switching between Sell/Rent/Exchange tabs before submission.
AC-02Preview screen accurately reflects every field entered, including images, before final submission.
AC-03Required-field validation blocks submission with clear inline errors rather than a silent failure.
AC-04Successfully created listings appear immediately in the user's own listings/'My Ads' and in relevant search feeds.
Test Scenarios
TC-01Create a Sell listing with all fields, submit, and verify it appears with correct type/price/fields on Property Detail.
TC-02Start a Rent listing, switch to Exchange mid-flow, and confirm shared fields (location, images) aren't lost and type-specific fields (rent price vs. exchange terms) reset/validate appropriately.
TC-03Attempt to submit with a required field missing (e.g. no images, no price) and confirm the app blocks submission with a visible error rather than sending an incomplete request.
TC-04Edit an existing listing via /edit-listing/[id] and confirm changes save without duplicating the listing or resetting untouched fields.
Switching identities changes context everywhere, with no data bleed
P0
Verify that POST auth/identity/switch correctly changes the active identity across the whole app, so that a user managing multiple identities never sees another identity's listings, chats, or favorites mixed into the current one. Note: switching TO a company/office identity currently lands on the ComingSoonGate (see mobile-company-office-gate) rather than a real home screen — verify that transition is clean, not broken.
AC-01After switching identity, Home/tabs immediately reflect the new role's UI (individual tabs, or the ComingSoonGate for company/office while the lock is active).
AC-02Listings, chats, and favorites shown are scoped strictly to the active identity.
AC-03Switching back to a previous identity restores its exact prior state (scroll position not required, but data must match).
AC-04Push notifications/chat sockets reconnect under the new identity's context rather than continuing to stream the old identity's events.
Test Scenarios
TC-01With an active chat open under identity A, switch to identity B and confirm identity A's conversation is no longer visible/reachable as B.
TC-02Switch identities repeatedly (A→B→A) and confirm no duplicated tabs, stale cached screens, or crash.
TC-03If a test account has a pre-existing company/office identity, switch to it and confirm landing cleanly on ComingSoonGate rather than a half-rendered tab bar underneath it.
Tap payment checkout completes and reconciles invoices correctly
P0
Verify the Tap payment gateway flow (POST payments/charge → redirect → /payment-callback → webhook → GET payments/status/:invoiceId) correctly reflects success and failure states, so that users are never charged without an invoice being marked paid, or shown 'success' when payment actually failed.
AC-01A successful Tap payment redirects to /payment-callback showing a success state, and the related invoice's status updates (visible in more/invoices).
AC-02A declined/cancelled Tap payment redirects to a failure state and does not mark the invoice as paid.
AC-03Webhook-driven status updates are reflected even if the user closes the app before the redirect completes (poll GET status/:invoiceId on next launch).
TC-01Complete a full checkout with Tap test card success credentials and confirm invoice + balance update.
TC-02Trigger a decline (Tap test card failure credentials) and confirm no invoice is falsely marked paid, and the user sees a clear failure message.
TC-03Start a payment, force-close the app before the in-app redirect fires, reopen, and confirm the invoice status still resolves correctly (webhook already landed server-side).
TC-04Double-submit a charge (rapid double-tap 'Pay') and confirm no duplicate charge/invoice is created.
Verify the ContentContainer responsive breakpoints (md:/lg: Tailwind classes per docs/plans/07-ipad-layout.md) render correctly on iPad form factors, so that the App Store review team (and real iPad users) don't see a stretched/broken phone layout.
App Store demo account has believable, working seeded data
P0
Verify the demo account (demo@buyootna.cloud, per docs/plans/08-demo-account.md) has working seeded properties, a draft listing, favorites, chats, and an active subscription, so that App Store reviewers logging in with this account see a fully functional app rather than empty screens that could trigger another 4.2.2-style rejection.