# MenuKosh — Testing Guide

How to verify every part of the PWA / push / real-time / sound build actually
works. Grouped by feature. Anything marked **(needs Reverb)** requires a running
Reverb server — see `DEPLOY.md` Section 0 for the hosting requirement.

---

## 1. Lighthouse PWA audit — target 90+

1. Open `https://menukosh.pinakra.com/login` in **desktop Chrome**.
2. DevTools (F12) → **Lighthouse** tab.
3. Check **Progressive Web App** (and Performance if you want), device
   **Mobile**, click **Analyze page load**.
4. Target: PWA checks all green. Confirm specifically:
   - ✅ Installable (manifest + service worker + icons)
   - ✅ Has a `<meta name="theme-color">`
   - ✅ Provides a valid `apple-touch-icon`
   - ✅ Registers a service worker that controls the page and `start_url`
   - ✅ Redirects HTTP → HTTPS

If "installable" fails, the usual cause is icons not reachable — verify
`/icons/icon-192.png` and `/icons/icon-512.png` return 200.

---

## 2. Android Chrome — install test

1. On an Android phone, open `https://menukosh.pinakra.com` in **Chrome**.
2. You should see the custom **"Install MenuKosh App"** banner at the bottom
   (from `install-app-prompt.blade.php`). Tap **Install**.
   - If the banner doesn't show, Chrome may also offer install via ⋮ menu →
     **Install app / Add to Home screen**.
3. Confirm the app appears on the home screen with the MenuKosh icon.
4. Open it — it should launch **standalone** (no browser address bar) in
   portrait, with the cyan status bar.
5. Turn off Wi-Fi/data and reopen — you should get the branded **offline page**
   (`/offline.html`), not Chrome's dinosaur.

---

## 3. iOS Safari — Add to Home Screen + push (iOS 16.4+)

1. On an iPhone, open `https://menukosh.pinakra.com` in **Safari**.
2. The install banner shows a **"How?"** button (iOS can't auto-install). Tap
   it — the bottom-sheet walkthrough appears with the animated arrow.
3. Follow it: **Share** → **Add to Home Screen** → **Add**.
4. Open MenuKosh **from the home-screen icon** (not Safari). It launches
   standalone.
5. **Push test (must be opened from the home screen, iOS 16.4+):**
   - Log in as a restaurant owner or staff member.
   - Go to Settings (owner) or the ⚙ Notification Settings disclosure (staff).
   - Toggle **Push Notifications** on → accept the iOS permission prompt.
   - Tap **Send Test Notification** → you should get a system notification.
   - ⚠️ If the toggle shows "Install MenuKosh to your Home Screen first", you
     opened it in Safari, not from the home-screen icon. iOS only allows web
     push for installed PWAs.

---

## 4. Web push — full end-to-end (tab closed)

The real test: does a **new order** reach a staff phone with the app closed?

1. On **device A** (staff phone): install MenuKosh, log in as staff/owner,
   enable push notifications (Section 3 step 5), then **fully close the app**.
2. On **device B** (or any browser): open the restaurant's public QR menu,
   add an item, and **place an order**.
3. On device A: within a few seconds a **"🔔 New Order #…"** notification
   should appear, even though the app is closed.
4. Tap it → it should open MenuKosh to that order's detail page.

Backend-only sanity check (no device needed), from the server:
```bash
php artisan tinker
>>> $subs = App\Models\PushSubscription::all();
>>> App\Jobs\SendPushNotification::dispatchSync($subs, ['title'=>'Test','body'=>'Hello','url'=>'/']);
```
Then check `storage/logs/laravel.log` for a `SendPushNotification: batch
complete` line with `sent > 0`. A `4xx`/expired result means that subscription's
device has unsubscribed (the job auto-deletes those).

---

## 5. Loud sound alert (needs Reverb, or use the Test Sound button)

The loud looping doorbell for an **open** dashboard:

1. Open the staff or owner dashboard.
2. Click anywhere once (browsers require a user gesture before audio can play —
   this "unlocks" audio).
3. **Quick check:** open the 🔔 sound widget in the header → **Test Sound**.
   You should hear the ~4-second alert.
4. **Real check (needs Reverb):** with the dashboard open on device A, place an
   order from device B. Within ~1 second you should hear the alert play **3
   times** loudly, see the order row appear highlighted, and the tab title
   flash "(1) New Order!".
5. Click the new order (or refocus the tab) → the looping sound stops.

---

## 6. Autoplay policy test (the "click to enable sound" banner)

Browsers block audio until the user interacts with the page. Verify the
fallback works:

1. Open the dashboard in a **fresh** browser profile (or after clearing site
   data) and **do not click anything**.
2. Trigger a new order (needs Reverb) — because audio is still locked, a
   persistent **"🔔 Enable Sound Alerts (Click here)"** banner should appear at
   the top instead of silently failing.
3. Click the banner → audio unlocks and the current order's alert plays.
4. Reload, click once anywhere, then trigger another order → this time it plays
   immediately with no banner (audio was unlocked by your click).

---

## 7. TWA install test (sideload the APK)

Before submitting to Play Store, test the actual Android build:

1. Generate the package in PWABuilder (see `PLAY_STORE_SUBMISSION.md`).
2. Transfer `app-release-signed.apk` to an Android phone.
3. Enable **Install unknown apps** for your file manager, tap the APK, install.
4. Open it — **critical check:** it must load **without a browser address
   bar**. If you see an address bar, Digital Asset Links verification failed:
   - Confirm `https://menukosh.pinakra.com/.well-known/assetlinks.json` is live
     and returns `application/json`.
   - Confirm the SHA-256 fingerprint in that file matches your signing key
     (`keytool -list -v -keystore signing.keystore`).
   - Note: the sideloaded APK uses your **upload key** fingerprint; the Play
     Store version uses the **Play App Signing** fingerprint — assetlinks.json
     must list **both** (see `PLAY_STORE_SUBMISSION.md` Section 1).

---

## 8. Play Store internal testing track

1. In Play Console, create an **Internal testing** release and upload the
   `.aab`.
2. Add 3–5 tester email addresses (their Google accounts) to the internal
   testers list.
3. Share the opt-in link with them; they install via Play Store.
4. Verify with testers: app opens standalone, login works, placing/receiving
   orders works, push notifications arrive.
5. Only promote to Production once internal testing is clean.

---

## 9. Multi-tenant isolation test (critical — security)

Confirm one restaurant can **never** see another's orders or notifications.

1. Set up two restaurants (A and B) with their own staff accounts.
2. Log in as **Restaurant A staff** on one device, **Restaurant B staff** on
   another.
3. Place an order at **Restaurant A**.
4. ✅ Restaurant A staff: gets the sound + live row + push.
5. ✅ Restaurant B staff: gets **nothing** — no sound, no row, no push.
6. Repeat placing an order at Restaurant B and confirm the reverse.

Backend checks:
- The broadcast channel is `private-restaurant.{id}` and
  `routes/channels.php` authorizes only users whose `restaurant_id` matches
  **and** whose role is staff/owner. Try (via browser devtools console on
  Restaurant B's dashboard) to subscribe to Restaurant A's channel:
  ```js
  window.Echo.private('restaurant.<A_id>')
  ```
  It should fail authorization (403 from `/broadcasting/auth`).
- Push: `SendPushNotification` is dispatched only with subscriptions scoped via
  `PushSubscription::forRestaurant($id)`, so a cross-tenant token is never in
  the batch.

---

## 10. Quick regression checklist (run after each deploy)

- [ ] Login works (owner, staff, super-admin)
- [ ] Public QR menu loads and an order can be placed
- [ ] Placing an order still returns success + tracking link
- [ ] Dashboard header shows sound 🔔 widget and (VPS) 🟢 Live indicator
- [ ] `/manifest.json`, `/offline.html`, `/privacy`, `/.well-known/assetlinks.json` all 200
- [ ] No errors in `storage/logs/laravel.log`
