> 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/flow_diagram.md).

# FleetOS Complete Flow Diagram

> Single source of truth. Every page, every button, every function. Updated: 2026-01-30

***

## WHAT IS LIVE ON fleetos.us RIGHT NOW

Production = `main` branch auto-deploys via Vercel (`fleet-os` project). All 5 phases of the zero-friction plan are deployed (commit `33c6374`+).

***

## CANONICAL COMPONENTS (use ONLY these)

| #  | Component                  | File                                 | Purpose                                                                                              |
| -- | -------------------------- | ------------------------------------ | ---------------------------------------------------------------------------------------------------- |
| 1  | **CleanLanding**           | `pages/CleanLanding.tsx`             | Landing page + login form + demo buttons                                                             |
| 2  | **UnifiedDashboard**       | `pages/UnifiedDashboard.tsx`         | THE dashboard (supplier + fleet). Has: jobs, contacts, CALL, WHATSAPP, EMAIL, ASSIGN, full lifecycle |
| 3  | **SupplierTodoList**       | `components/SupplierTodoList.tsx`    | Job list rendered INSIDE UnifiedDashboard. Has: CALL, WHATSAPP, ASSIGN, status actions               |
| 4  | **RequestResponseView**    | `components/RequestResponseView.tsx` | Magic link response (external, no login). Accept/ETA/Decline + contact sender                        |
| 5  | **ManualRequestForm**      | `forms/ManualRequestForm.tsx`        | Supplier creates a job manually                                                                      |
| 6  | **FleetRequestForm**       | `forms/FleetRequestForm.tsx`         | Fleet creates request to specific supplier                                                           |
| 7  | **InviteFlow**             | `forms/InviteFlow.tsx`               | Generate invite link, share via WhatsApp                                                             |
| 8  | **RequestSuccessPage**     | `pages/RequestSuccessPage.tsx`       | Confirmation after request submitted                                                                 |
| 9  | **SupplierOnboardingPage** | `pages/SupplierOnboardingPage.tsx`   | Multi-step supplier signup                                                                           |
| 10 | **SupplierDirectory**      | `pages/SupplierDirectory.tsx`        | Browse suppliers by category                                                                         |

All paths are relative to `components/fleetos/`.

***

## LEGACY COMPONENTS (DO NOT USE, DO NOT MODIFY)

6 legacy files were deleted (2026-01-30). 3 remain because they serve live URL routes:

| File                                    | Status       | Why kept                             |
| --------------------------------------- | ------------ | ------------------------------------ |
| `legacy/FleetOSRequestTrackingPage.tsx` | STILL ROUTED | Serves `/track/:token` URL           |
| `legacy/PublicRequestFormHandler.tsx`   | STILL ROUTED | Serves `/request/:slug` URL          |
| `legacy/PublicRequestPage.tsx`          | STILL USED   | Imported by PublicRequestFormHandler |

**Deleted:** FleetOSLoginPage, FleetOSAuthVerify, FleetOSQuickAccess, FleetOSMobileTires, ViralAnalyticsDashboard, WhatsAppTest.

***

## COMPLETE USER FLOWS

### FLOW 1: New Supplier Signs Up

```
CleanLanding [I'M A SUPPLIER]
  → navigate('FLEETOS_SUPPLIER_ONBOARDING')
  → App.tsx renders SupplierOnboardingPage
    → user fills: name, email, phone, company, services
    → creates user (users table)
    → creates company (companies table)
    → creates contact (ContactService.getOrCreate)
    → seeds 6 demo requests (service_requests)
    → saves fleetos_user to localStorage
    → navigate('FLEETOS_SUPPLIER_DASHBOARD')
  → App.tsx renders UnifiedDashboard(userType="supplier")
    → loads company requests via getCompanyServiceRequests()
    → shows Jobs tab
```

### FLOW 2: New Fleet Signs Up

```
CleanLanding [I'M A FLEET]
  → navigate('FLEETOS_FLEET_ONBOARDING')
  → App.tsx renders inline fleet onboarding form
    → user fills: name, email, company
    → creates user, company, contact
    → seeds 6 demo supplier relationships
    → saves fleetos_user to localStorage
    → navigate('FLEETOS_FLEET_DASHBOARD')
  → App.tsx renders UnifiedDashboard(userType="fleet")
```

### FLOW 3: Returning User Logs In

```
CleanLanding [LOGIN] → scrolls to daily-access form
  → user enters email, clicks submit
  → direct login (no email sent, zero friction)
    → find/create company by domain
    → find/create user by email
    → create emergent contact
    → save fleetos_user to localStorage
    → navigate('FLEETOS_SUPPLIER_DASHBOARD')
```

### FLOW 4: Session Restore (no login needed)

```
Browser opens fleetos.us (or localhost:3000)
  → App.tsx getInitialView():
    → reads localStorage('fleetos_user')
    → user.id !== 'guest' && user.activeRole exists?
      → SUPPLIER → FLEETOS_SUPPLIER_DASHBOARD
      → FLEET → FLEETOS_FLEET_DASHBOARD
    → renders UnifiedDashboard directly
```

### FLOW 5: Supplier Responds via Magic Link (S3)

```
/respond?requestId={ID}&phone={PHONE}
  → App.tsx URL routing extracts params
  → renders RequestResponseView

  → loads request via QueryService.getRequestById()
  → shows request card (fleet name, vehicle, location, urgency)
  → expanded card shows:

    LIVE version:      [ACCEPT] [NEED 30 MINS] [CAN'T HELP]
    LOCAL fix version: [CALL FLEET] [WHATSAPP]
                       [custom ETA text input if SET ETA clicked]
                       [ACCEPT] [SET ETA] [CAN'T HELP]

  → ACCEPT: ask name (first-time) → acceptRequest() → acknowledged
  → SET ETA / NEED 30 MINS: acknowledgeRequest() with note
  → CAN'T HELP: declineRequest() → declined
```

### FLOW 6: Supplier Works a Job (Dashboard)

```
UnifiedDashboard (supplier) — Jobs Tab

  PENDING request card (collapsed):
    → click to expand

  PENDING request card (expanded):
    [ACCEPT] → acknowledgeRequest() → status: acknowledged
    [ASSIGN] → team member overlay → reassignRequest()
    [DECLINE] → declineRequest()

  ACKNOWLEDGED request card (expanded):
    [START] → startRequest() → status: in_progress
    [ASSIGN] → reassign
    [CALL] [WHATSAPP] [EMAIL] → contact fleet (2-tier)

  IN PROGRESS request card (expanded):
    [DONE] → completeRequest() → status: completed
    [ASSIGN] → reassign
    [CALL] [WHATSAPP] [EMAIL] → contact fleet

  COMPLETED: view-only with timestamps
```

### FLOW 7: Fleet Creates a Request

```
UnifiedDashboard (fleet) → My Suppliers tab
  → click supplier → [+ ADD JOB]
  → navigate('FLEETOS_FLEET_CREATE_REQUEST')
  → FleetRequestForm: vehicle, location, description, urgency
  → QueryService.createServiceRequest()
  → generates magic link for supplier
  → navigate('FLEETOS_REQUEST_SUCCESS')
  → RequestSuccessPage with tracking URL
```

### FLOW 8: Public Tracking (no login)

```
/track/{tracking_token}
  → App.tsx extracts token
  → renders FleetOSRequestTrackingPage (LEGACY — still active)
  → queries service_requests by token
  → shows timeline: Created → Acknowledged → In Progress → Completed
```

### FLOW 9: Invite Counterparty

```
UnifiedDashboard → [INVITE]
  → navigate('FLEETOS_INVITE_FLEET' or 'FLEETOS_INVITE_SUPPLIER')
  → InviteFlow: generates shareable magic link
  → [COPY LINK] or [SHARE VIA WHATSAPP]
  → invited user clicks → onboarding
```

***

## VIEW ROUTING TABLE (App.tsx)

| View                                  | Component                  | Status                                |
| ------------------------------------- | -------------------------- | ------------------------------------- |
| `FLEETOS`                             | CleanLanding               | CANONICAL                             |
| `FLEETOS_SUPPLIER_ONBOARDING`         | SupplierOnboardingPage     | CANONICAL                             |
| `FLEETOS_FLEET_ONBOARDING`            | Inline in App.tsx          | CANONICAL                             |
| `FLEETOS_SUPPLIER_DASHBOARD`          | UnifiedDashboard(supplier) | CANONICAL                             |
| `FLEETOS_FLEET_DASHBOARD`             | UnifiedDashboard(fleet)    | CANONICAL                             |
| `FLEETOS_SUPPLIER_ADD_MANUAL_REQUEST` | ManualRequestForm          | CANONICAL                             |
| `FLEETOS_FLEET_CREATE_REQUEST`        | FleetRequestForm           | CANONICAL                             |
| `FLEETOS_INVITE_FLEET`                | InviteFlow(supplier)       | CANONICAL                             |
| `FLEETOS_INVITE_SUPPLIER`             | InviteFlow(fleet)          | CANONICAL                             |
| `FLEETOS_REQUEST_SUCCESS`             | RequestSuccessPage         | CANONICAL                             |
| `FLEETOS_REQUEST_RESPONSE`            | RequestResponseView        | CANONICAL                             |
| `FLEETOS_PUBLIC_REQUEST`              | PublicRequestFormHandler   | LEGACY (still serving /request/:slug) |
| `FLEETOS_REQUEST_TRACKING`            | FleetOSRequestTrackingPage | LEGACY (still serving /track/:token)  |

**11 canonical routes + 2 legacy routes still serving live URLs.**

***

## FEATURE MATRIX

| Feature             | UnifiedDashboard | SupplierTodoList | RequestResponseView |
| ------------------- | :--------------: | :--------------: | :-----------------: |
| Accept              |        YES       |        YES       |         YES         |
| Start               |        YES       |        YES       |          NO         |
| Complete            |        YES       |        YES       |          NO         |
| Decline             |        YES       |        YES       |         YES         |
| Custom ETA          |        NO        |        NO        |   YES (local fix)   |
| CALL                |   YES (2-tier)   |   YES (2-tier)   |   YES (local fix)   |
| WHATSAPP            |   YES (2-tier)   |   YES (2-tier)   |   YES (local fix)   |
| EMAIL               |   YES (2-tier)   |        NO        |          NO         |
| ASSIGN              |   YES (overlay)  |   YES (overlay)  |          NO         |
| View contacts tab   |        YES       |        NO        |          NO         |
| Invite counterparty |        YES       |        NO        |          NO         |
| Create request      |        YES       |        NO        |          NO         |

***

## SERVICES

| Service             | File                                  | What it does                              |
| ------------------- | ------------------------------------- | ----------------------------------------- |
| QueryService        | `services/shared/QueryService.ts`     | ALL request CRUD                          |
| ContactService      | `services/shared/ContactService.ts`   | Emergent contacts                         |
| AuthService         | `services/AuthService.ts`             | Magic links + sessions (LEGACY for login) |
| NotificationService | `services/NotificationService.ts`     | Status change notifications               |
| EventLogService     | `services/shared/EventLogService.ts`  | Audit trail                               |
| PermissionService   | `services/PermissionService.ts`       | Access control                            |
| InviteService       | `services/InviteService.ts`           | Viral invite links                        |
| MagicLinkService    | `services/shared/MagicLinkService.ts` | Token encode/decode                       |

***

## DB STATE (as of 2026-01-30)

| Company           | ID            | Domain   | Active Requests                         |
| ----------------- | ------------- | -------- | --------------------------------------- |
| T420              | `87959c56...` | t420.io  | 3 (all completed)                       |
| joes mobile tires | `3489faf0...` | tires.co | 2 (both acknowledged)                   |
| Ex Fleet          | `06feca30...` | —        | fleet\_company on the 2 active requests |

**Why dashboard is empty after login as <zane@t420.io>:** T420 company has 0 pending/active requests. All 3 are completed. This is correct behavior — the dashboard isn't broken, there's just no active work.

***

## ARCHITECTURE DECISION: COMPANY-OWNED

Work belongs to **companies**, not individual users. This is the fundamental architectural decision.

* All `service_requests` are scoped to `fleet_company_id` + `supplier_company_id`
* Any member of a company sees all company work (workshop board model)
* Users are actors: `submitted_by_user_id` (audit), `assigned_to_user_id` (current worker)
* Emergency access, 24/7 handoffs, and staff turnover all work because work is company-scoped
* This is what differentiates FleetOS from WhatsApp (team visibility, boss oversight, audit trail)

See `docs/FLEETOS_ROUTING_ACCESS_BIBLE.md` for the full org-first routing rules.

***

## WHATSAPP & TWILIO SETUP

### Edge Functions (Supabase)

* **send-whatsapp**: Outgoing messages via Twilio API
* **whatsapp-webhook**: Incoming replies, parses commands (ACK, ACCEPT, DECLINE, HELP)

### Twilio Secrets (set via `supabase secrets set`)

* `TWILIO_ACCOUNT_SID` — Twilio account ID
* `TWILIO_AUTH_TOKEN` — Twilio auth (server-side only, NEVER expose to frontend)
* `TWILIO_WHATSAPP_FROM` — `whatsapp:+14155238886` (sandbox) or production number

### Webhook Configuration

* Twilio Console > Messaging > WhatsApp Sandbox Settings
* "When a message comes in" → `https://bsbjwjpgiangjqqqxota.supabase.co/functions/v1/whatsapp-webhook`
* Method: POST

### Deploy Commands

```bash
supabase functions deploy send-whatsapp
supabase functions deploy whatsapp-webhook
```

### Production Upgrade

Request dedicated WhatsApp Business number via Twilio Console > Messaging > Senders. Update: `supabase secrets set TWILIO_WHATSAPP_FROM=whatsapp:+1XXXXXXXXXX`

***

## SECURITY RULES

### Frontend-safe variables (VITE\_ prefix OK)

* `VITE_SUPABASE_URL` — public Supabase URL
* `VITE_SUPABASE_ANON_KEY` — public key, respects RLS
* `VITE_APP_URL` — app domain

### Server-side ONLY (NEVER use VITE\_ prefix)

* `SUPABASE_SERVICE_ROLE_KEY` — bypasses ALL RLS (complete DB access)
* `TWILIO_AUTH_TOKEN` — can send messages
* `SENDGRID_API_KEY` — can send emails
* `MAGIC_LINK_SECRET` — can forge magic-link tokens (read by the sign-token edge function)

**Rule**: `VITE_` prefix = bundled into frontend JS = visible to anyone in DevTools.

***

## RULES FOR AGENTS

1. **NEVER create a new component** — everything needed already exists
2. **NEVER modify files in `legacy/`** — they should be deleted, not improved
3. **If a feature needs adding**, add it to the CANONICAL component from the table above
4. **UnifiedDashboard is THE dashboard** — all job management features live here
5. **SupplierTodoList is the job list INSIDE UnifiedDashboard** — not a separate page
6. **RequestResponseView is EXTERNAL ONLY** — magic link, no login, simple actions
7. **Call/WhatsApp/Assign already exist** in UnifiedDashboard + SupplierTodoList as 2-tier
8. **Read this document BEFORE writing code**
9. **Read `docs/fleetos/ROUTING_ACCESS_BIBLE.md`** for auth/access rules


---

# 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/flow_diagram.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.
