> For the complete documentation index, see [llms.txt](https://t420.gitbook.io/t420/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://t420.gitbook.io/t420/live_test_plan.md).

# FleetOS Live Test Plan — Sprint 2

> **Run on:** <https://fleetos.us> **Date:** 2026-02-09 **Focus:** WhatsApp/Twilio, Magic Links, Emergent Contacts, Viral Elements, Team Access **Time:** \~45 minutes (with two phones) **Pre-req:** Clear localStorage before starting (DevTools > Application > Local Storage > delete all)

***

## SETUP CHECKLIST

Before starting, confirm these are in place:

* [ ] **Two WhatsApp-capable phones** (yours = Fleet user, friend/second phone = Supplier)
* [ ] **Twilio WhatsApp Sandbox** connected on both phones (or production number active)
  * Sandbox: Text `join <sandbox-keyword>` to `+1 415 523 8886` on WhatsApp
* [ ] **Supabase Dashboard** open at <https://supabase.com/dashboard> (for verification queries)
* [ ] **Browser DevTools** Console tab open (magic links log to console in dev mode)
* [ ] **Environment variables** deployed (check Vercel > fleet-os > Settings > Environment Variables):
  * `VITE_TWILIO_ACCOUNT_SID` = `ACxxxx...`
  * `VITE_TWILIO_AUTH_TOKEN` = set
  * `VITE_TWILIO_WHATSAPP_FROM` = `whatsapp:+14155238886` (sandbox) or your production number
  * `VITE_SUPABASE_URL` = `https://your-project.supabase.co`
  * `VITE_SUPABASE_ANON_KEY` = set
  * `VITE_APP_URL` = `https://fleetos.us`
* [ ] **Twilio Webhook** configured:
  * Twilio Console > Messaging > WhatsApp Sandbox > "When a message comes in"
  * URL: `https://{SUPABASE_PROJECT_REF}.supabase.co/functions/v1/whatsapp-webhook`
  * Method: POST

***

## TEST 1: Fleet Signup (Baseline)

**Goal:** Fresh fleet account with demo data

1. Open **incognito window** → `https://fleetos.us`
2. Click **"I'm a Fleet Operator"** (or go directly to `/?view=FLEETOS_FLEET_ONBOARDING`)
3. Fill in:
   * Fleet Name: your fleet company name (required)
   * Your Name: your name (optional)
   * Work Email: your real email (required, unique)
   * WhatsApp Number: your real phone number, Phone 1 (optional, for notifications)
4. Click **"GET STARTED"**
5. Wait for dashboard to load

**Expected:**

* [ ] \[y ] Dashboard shows **"Today's Dispatch"** title
* [ ] **"Fleet Manager"** role bar visible (NOT "Supplier Dashboard")
* [ ] 6 demo job cards visible with URGENT / TODAY / SCHEDULED tags
* [ ] Metrics row: Unassigned, Awaiting, Active, Today
* [ ] Filter pills: All, Urgent, Today, Active, Done
* [ ] Header buttons: + Add, Share, Log out

**Verify in Supabase:**

```sql
SELECT company_id, company_name, company_type FROM companies ORDER BY created_at DESC LIMIT 5;
-- Should see your fleet company with company_type='fleet'

SELECT * FROM service_requests WHERE created_via = 'demo_seed' ORDER BY created_at DESC LIMIT 6;
-- Should see 6 demo requests
```

**📝 Note your fleet company\_id:** `________________`

***

## TEST 2: Supplier Signup (Baseline)

**Goal:** Fresh supplier account on second phone

1. On **second phone** (or second incognito window): `https://fleetos.us`
2. Click **"I'm a Supplier"** (or `/?view=FLEETOS_SUPPLIER_ONBOARDING`)
3. Fill in:
   * Business Name: `Test Tyres [today's date]`
   * Your Name: Friend's name
   * Work Email: different email
4. Click **"GET STARTED"**

**Expected:**

* [ ] Dashboard shows **"My Jobs"** title
* [ ] **"Supplier Dashboard"** role bar visible (NOT "Fleet Manager")
* [ ] 6 demo job cards visible
* [ ] Metrics row: Action, Active, Done, Earned
* [ ] Filter pills: All, Action Needed, Active, Done
* [ ] PENDING\_RESPONSE cards auto-expanded with Accept/Decline panel

**📝 Note your supplier company\_id:** `________________`

***

## TEST 3: Fleet Adds Supplier as Contact

**Goal:** Connect the two accounts so WhatsApp flow can be tested

1. As **Fleet user** (Phone 1 browser): Go to **My Suppliers** tab
2. Click **"+ Add Supplier"**
3. Fill in:
   * Name: Supplier's company name, e.g. "Test Tyres" (required — placeholder says "Name (required)")
   * WhatsApp / Phone: **Supplier's real WhatsApp number**, Phone 2 (placeholder "+27...")
   * Category: "Tyres" (placeholder "Category (e.g. Tyres)")
4. Click **"ADD CONTACT"**

**Expected:**

* [ ] New supplier contact card appears in My Suppliers tab
* [ ] Phone number shows correctly

**Verify in Supabase:**

```sql
SELECT * FROM contacts WHERE company_id = 'YOUR_FLEET_COMPANY_ID' ORDER BY created_at DESC LIMIT 5;
-- Should see the supplier contact with their phone number
```

***

## TEST 4: Fleet Creates Request → WhatsApp Sent to Supplier 🔑

**Goal:** End-to-end WhatsApp notification with magic link

1. As **Fleet user**: Click **"+ Add"** in header to open the **Add Job** modal
2. Select supplier: choose **"EXISTING CONTACT"** tab, then pick the supplier you just added from the dropdown
3. Fill in:
   * Vehicle: `Truck #99` (select from saved vehicles, or click **"+ NEW"** and type it in)
   * Location: `123 Test Road, Johannesburg`
   * What's Needed: `Live test - flat tire needs replacement`
   * Technician Name: (optional, skip for now)
   * Bay / Workspace: (optional, skip for now)
   * Part Needed: (optional, skip for now)
   * Urgency: click **"NOW"** (maps to URGENT)
4. Click **"ADD JOB"**

**Expected:**

* [ ] Request created, appears in dashboard as "Awaiting Reply"
* [ ] **Phone 2 (Supplier) receives WhatsApp message** within 30 seconds
* [ ] WhatsApp message contains:
  * Request details (vehicle, location)
  * A **magic link URL** to respond (e.g., `fleetos.us/respond?requestId=...`)
* [ ] If WhatsApp NOT received: Check browser console for `[DEMO MODE]` message (means Twilio not configured)

**Verify in Supabase:**

```sql
-- Check request was created
SELECT request_id, status, urgency, vehicle_identifier, supplier_company_id
FROM service_requests
WHERE vehicle_identifier = 'Truck #99'
ORDER BY created_at DESC LIMIT 1;
-- Status should be 'pending'

-- Check notification was sent
SELECT notification_id, channel, delivery_status, created_at
FROM notifications
ORDER BY created_at DESC LIMIT 5;
-- Should see channel='whatsapp', check delivery_status
```

**📝 Note the request\_id:** `________________` **📝 Screenshot the WhatsApp message received**

***

## TEST 5: Supplier Clicks Magic Link → Responds 🔑

**Goal:** Magic link one-tap response flow

1. On **Phone 2** (Supplier): Tap the magic link in the WhatsApp message
2. Browser opens `fleetos.us/respond?requestId=XXX&phone=+XXXX`

**Expected — Step-by-step flow in RequestResponseView:**

* [ ] **Step 1 (VIEW):** Request details shown — vehicle, location, description, urgency badge
* [ ] Fleet company name visible
* [ ] "Respond" button visible

3. Tap **"Respond"**

* [ ] **Step 2 (QUOTE):** Quote input shown

4. Enter quote: `R 2500`
5. Tap **"Next"**

* [ ] **Step 3 (ETA):** ETA input shown

6. Enter ETA: `30 minutes`
7. Tap **"Confirm"**

* [ ] **Step 4 (CONFIRMED):** Confirmation screen — "Response sent!"
* [ ] No login was required at any point
* [ ] No signup was required at any point

**Now check Fleet side:** 8. On **Phone 1** (Fleet browser): Refresh the dashboard

* [ ] The "Truck #99" card now shows **"Accepted"** status (green badge)
* [ ] Quote amount visible (R 2500)

**Verify in Supabase:**

```sql
SELECT status, quoted_amount, assigned_to_name
FROM service_requests
WHERE request_id = 'YOUR_REQUEST_ID';
-- status should be 'accepted', quoted_amount should be 2500
```

***

## TEST 6: Emergent Contact Creation 🔑

**Goal:** Verify zero-friction contact creation via magic link

**What should have happened in Test 5:** When the supplier clicked the magic link, `ContactService.getOrCreate()` was called. If this was a new phone number, a contact was created **without signup**.

**Verify in Supabase:**

```sql
-- Check if emergent contact was created
SELECT contact_id, display_name, contact_type, contact_value, created_at
FROM contacts
WHERE contact_value LIKE '%SUPPLIER_PHONE_DIGITS%'
ORDER BY created_at DESC;
-- Should find a contact row created by the magic link click

-- Check the contact is linked to the fleet's company
SELECT c.contact_id, c.display_name, c.company_id, co.name as company_name
FROM contacts c
JOIN companies co ON c.company_id = co.company_id
WHERE c.contact_value LIKE '%SUPPLIER_PHONE_DIGITS%';
```

**Expected:**

* [ ] Contact row exists with the supplier's phone number
* [ ] `contact_type` = `phone`
* [ ] Contact was created automatically (no signup form)

***

## TEST 7: Emergent Contact with Unknown Number 🔑

**Goal:** Send request to a phone that has NEVER signed up

1. As **Fleet user**: Create a new request
2. Add a contact with a **third phone number** (someone who has never used FleetOS)
   * Or use a number you control but haven't registered
3. Submit the request
4. When that person clicks the magic link in WhatsApp and responds:

**Expected:**

* [ ] They see the full response flow (no login/signup needed)
* [ ] After responding, check Supabase: new `contacts` row created for that phone number
* [ ] That contact now appears in Fleet's "My Suppliers" tab
* [ ] This person was NEVER asked to create an account

***

## TEST 8: WhatsApp Inbound Commands (Webhook) 🔑

**Goal:** Test the webhook that processes inbound WhatsApp replies

**Pre-req:** Twilio webhook must be configured (see Setup Checklist)

1. From **Phone 2** (Supplier): Reply to the WhatsApp thread from FleetOS

**Test each command:**

| Send This         | Expected Response                           | DB Change               |
| ----------------- | ------------------------------------------- | ----------------------- |
| `HELP`            | Receive command list message                | None                    |
| `ACK`             | Receive "Request acknowledged" confirmation | `status → acknowledged` |
| `ACCEPT`          | Receive "Job accepted" confirmation         | `status → accepted`     |
| `DECLINE Too far` | Receive "Request declined" confirmation     | `status → declined`     |

2. After each command, check the **Fleet dashboard** (refresh)

**Expected:**

* [ ] `HELP` returns list of available commands
* [ ] `ACK` updates card to "Acknowledged" status
* [ ] `ACCEPT` updates card to "Accepted" status
* [ ] `DECLINE` removes card or shows "Declined"
* [ ] Fleet dashboard reflects changes in real-time (on refresh)

**Verify in Supabase:**

```sql
SELECT request_id, status, updated_at
FROM service_requests
WHERE fleet_company_id = 'YOUR_FLEET_COMPANY_ID'
ORDER BY updated_at DESC LIMIT 5;
```

**⚠️ If webhook not working:**

* Check Twilio Console > Messaging > Logs for errors
* Check Supabase > Edge Functions > `whatsapp-webhook` > Logs
* Verify webhook URL is correct: `https://{PROJECT_REF}.supabase.co/functions/v1/whatsapp-webhook`

***

## TEST 9: Complete Job Flow (Dashboard)

**Goal:** Full lifecycle via dashboard action panels

1. As **Supplier user**: Find an "In Progress" card on dashboard
   * If none exists: Accept a pending card first, then it should progress
2. Expand the card
3. Find **"Mark complete"** panel

**Expected:**

* [ ] Currency label shown (e.g. "ZAR")
* [ ] "Final cost" input visible
* [ ] VAT type selector visible (Incl. VAT / Excl. VAT)
* [ ] "Note (optional)" input visible
* [ ] "Attach invoice" button visible
* [ ] "Complete Job" button visible

4. Enter final cost: `2800`
5. Select VAT type: `Incl. VAT` (or `Excl. VAT`)
6. Enter note: `Replaced with new Goodyear 285/70R19.5`
7. Optionally attach an invoice file
8. Click **"Complete Job"**

**Expected:**

* [ ] Card status changes to **"Done"** (green badge)
* [ ] **Earned** metric in supplier dashboard updates
* [ ] Card moves to completed section

**Verify in Supabase:**

```sql
SELECT status, final_cost, completed_at
FROM service_requests
WHERE request_id = 'THE_REQUEST_ID';
-- status='completed', final_cost=2800
```

***

## TEST 10: Team Access / Share Link 🔑

**Goal:** Share dashboard with a team member (no signup)

1. As **Fleet user**: Click **"Share"** button in header
2. A share modal/link should appear
3. Copy the team access link (format: `fleetos.us/team?token=BASE64...`)
4. Open the link in a **new incognito window** (or send to a different device)

**Expected:**

* [ ] Link opens successfully
* [ ] User is asked for their name (or auto-joins)
* [ ] Dashboard loads showing the **same fleet data** (same job cards)
* [ ] Role bar shows "Fleet Manager" (same company)
* [ ] No signup was required — just the link

**Verify in Supabase:**

```sql
-- Check new profile was created for the team member
SELECT profile_id, company_id, display_name, created_at
FROM user_profiles
WHERE company_id = 'YOUR_FLEET_COMPANY_ID'
ORDER BY created_at DESC LIMIT 5;
-- Should see multiple profiles for the same company
```

***

## TEST 11: Viral Triggers 🔑

**Goal:** Verify viral moments fire at the right times

Viral moments are **probabilistic** — they won't always fire. Do these actions and look for toasts/share prompts:

| Action                     | Viral Moment     | Probability | What to Look For                     |
| -------------------------- | ---------------- | ----------- | ------------------------------------ |
| Create first real request  | `FIRST_REQUEST`  | 80%         | Share prompt / toast                 |
| Supplier acknowledges      | `ACKNOWLEDGMENT` | 50%         | "Your supplier acknowledged!" prompt |
| Job completed              | `RELIEF`         | 60%         | "Job done!" share prompt             |
| 5th job total              | `MILESTONE_5`    | 90%         | Milestone celebration toast          |
| Supplier gives great quote | `PRIDE`          | 40%         | "Great quote!" share moment          |

**Test steps:**

1. Perform the above actions naturally through the test flow
2. Watch for toast notifications or share prompts after each action
3. If you don't see one, it's likely the probability didn't trigger — try again

**Verify in Supabase:**

```sql
SELECT * FROM viral_events ORDER BY created_at DESC LIMIT 10;
-- Check moment_type, triggered_by, company_id, converted (true/false)
```

**Expected:**

* [ ] At least 1-2 viral events appear in the table after running through Tests 4-9
* [ ] Events have correct `moment_type` values
* [ ] `cooldown` is respected (no duplicate moment for same user within 7 days)

***

## TEST 12: Invite Flow (Supplier Invites Fleet)

**Goal:** Bidirectional invite via invite code

1. As **Supplier user**: Go to **"My Fleets"** tab
2. Click **"+ Invite Fleet"**
3. Fill in:
   * Company name: `New Fleet Inc`
   * Email: a real email you can check
4. Submit

**Expected:**

* [ ] Invite code generated (format: `ABC-123-XYZ`)
* [ ] Confirmation shown
* [ ] Email sent to the fleet email with invite link

5. Check the email inbox
6. Click the invite link

**Expected:**

* [ ] Opens FleetOS with the invite context
* [ ] Relationship auto-created between supplier and fleet companies

**Verify in Supabase:**

```sql
SELECT invite_id, invite_code, from_company_id, to_email, status, expires_at
FROM fleetos_invites
ORDER BY created_at DESC LIMIT 5;
-- status should go from 'pending' to 'accepted' after clicking

SELECT * FROM fleetos_relationships
WHERE supplier_company_id = 'YOUR_SUPPLIER_COMPANY_ID'
ORDER BY created_at DESC LIMIT 5;
-- New relationship should appear
```

***

## TEST 13: Login / Re-Authentication

**Goal:** Verify session persistence and magic link login

1. As **Fleet user**: Click **"Log out"**
2. Verify: Returned to landing page
3. Refresh page — should stay on landing (NOT auto-redirect)
4. Click **"Login"**
5. Enter the fleet email used in Test 1
6. Click **"GO"**

**Expected:**

* [ ] Dashboard loads with all previous data intact
* [ ] Same job cards, same contacts, same company name
* [ ] No data loss from logout/login cycle

***

## TEST 14: Mobile Responsiveness

**Goal:** All flows work on actual mobile device

1. Open `https://fleetos.us` on your phone (not DevTools emulator)
2. Complete a quick signup
3. Verify:
   * [ ] Landing page fits screen, no horizontal scroll
   * [ ] Dashboard fits within 375px width
   * [ ] Metrics row shows all 4 items
   * [ ] Filter pills scroll horizontally
   * [ ] Job cards expand/collapse on tap
   * [ ] Action buttons (Accept/Decline) are tappable
   * [ ] WhatsApp links open WhatsApp app directly

***

## RESULTS TABLE

| #  | Test                           | Pass ✅ / Fail ❌ | Notes |
| -- | ------------------------------ | --------------- | ----- |
| 1  | Fleet Signup                   |                 |       |
| 2  | Supplier Signup                |                 |       |
| 3  | Fleet Adds Supplier Contact    |                 |       |
| 4  | Request → WhatsApp Sent        |                 |       |
| 5  | Magic Link → Supplier Responds |                 |       |
| 6  | Emergent Contact Created       |                 |       |
| 7  | Unknown Number → Emergent      |                 |       |
| 8  | WhatsApp Inbound Commands      |                 |       |
| 9  | Complete Job Flow              |                 |       |
| 10 | Team Access / Share Link       |                 |       |
| 11 | Viral Triggers                 |                 |       |
| 12 | Invite Flow                    |                 |       |
| 13 | Login / Re-Auth                |                 |       |
| 14 | Mobile Responsiveness          |                 |       |

***

## TROUBLESHOOTING

### WhatsApp not received

1. Check browser console for `[DEMO MODE]` — means `VITE_SUPABASE_URL` not set
2. Check Supabase Edge Function logs: Dashboard > Edge Functions > `send-whatsapp` > Logs
3. Check Twilio Console > Messaging > Logs
4. Verify Twilio Sandbox is active (re-join if expired: text `join <keyword>` to `+1 415 523 8886`)

### Magic link doesn't load

1. Check the URL format: should be `fleetos.us/respond?requestId=UUID&phone=+XXXX`
2. Check if token expired (24h default): decode the base64 token, check `exp` field
3. Check browser console for errors

### Webhook commands not working

1. Verify Twilio webhook URL: `https://{PROJECT}.supabase.co/functions/v1/whatsapp-webhook`
2. Check Supabase Edge Function logs for `whatsapp-webhook`
3. Verify Twilio signature validation is matching (check `TWILIO_AUTH_TOKEN` env var in Supabase)

### Emergent contact not created

1. Check Supabase `contacts` table for the phone number (digits only, no formatting)
2. Check `respond-to-request` edge function logs
3. The contact is created by `ContactService.getOrCreate()` — check if it ran

### Viral events not appearing

1. Probability-based — may not trigger every time
2. Check 7-day cooldown: same user + same moment\_type within 7 days = suppressed
3. Check `ViralTriggerEngine.ts` for exact probabilities per moment type

***

## NEXT STEPS

After running all tests, document any failures in the Notes column above. Priority fixes: WhatsApp delivery > Magic link flow > Emergent contacts > Viral elements.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://t420.gitbook.io/t420/live_test_plan.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
