# Carrier Dispatch — Pilot paperwork behind the Pro plan (2026-09-13)

Source: Nash, voice note 2026-09-13 (evening).

> "When they go on an active trip under the My Pilot section, they can see the pilot paperwork in here if they are Pro. They will see the COI, the certificate, the license, and all that… only if they are Pro. If they are not, we could have an incentive… upgrade the product to see the paperwork. This way we give them a reason to upgrade to a Pro membership."

Scope per the task-wording rule: **Carrier Dispatch Trip View only** (`/cd-trip-workspace/<trip number>`, section 3, "My Pilot" tab). Nothing changes for the freight broker, the pilot views or the driver apps unless a task below says so.

---

## Requirements extracted (nothing added)

| # | Requirement | Where |
|---|---|---|
| P1 | On an active trip, the carrier dispatcher's **My Pilot** tab shows the pilot's paperwork: certificate of insurance (COI), certification, license "and all that". | CD trip view → section 3 → My Pilot |
| P2 | The paperwork is visible **only** to a carrier on the **Pro** subscription. | plan gate |
| P3 | A carrier who is **not** Pro sees an **incentive** in the same place: upgrade to see the paperwork. | locked state |
| P4 | Purpose: give carriers a reason to upgrade to Pro (advertising). | copy tone |

---

## Current state (verified in the codebase)

- **My Pilot tab exists** for the carrier and broker: `src/components/app/pilot-tools/my-pilot-tab.tsx` (`MyPilotTab`, `MyPilotEntry`). Rendered from real participants in `src/components/app/trip-workspace/trip-workspace.tsx` (`MyPilotWorkspaceTab`) and from demo data in the pilot shell's `CarrierSidePreview` (`/admin/pilot-preview/<ref>?as=carrier`). It shows name, kind, phone, email, access/states, status, pilot car, dispatch, invited-by, and pilot invoices (carrier). **No paperwork is shown today.**
- **Pilot documents exist only in the replica (demo data):** `src/lib/demo/pilot.ts` — `DEMO_PILOT_COMPANY.documents` (COI, W-9, business license, good standing, company documents, state company certification) and `DEMO_PILOT_DRIVERS[].documents` (W-9, driver license, COI, pilot car / escort certification, state certifications). Labels and required flags live in `src/lib/domain/pilot.ts` (`PILOT_DRIVER_DOCUMENTS`, `PILOT_COMPANY_DOCUMENTS`). Statuses: Not Uploaded / Uploaded / Approved / Expiring Soon / Expired, with expiration dates. Uploads are stored in sessionStorage (`PILOT_COMPANY_DOCS_KEY`, driver docs key) — no real files, no backend.
- **Real pilot participants have no documents.** Pilot accounts are Phase 1 replicas; a real `trip_participants` row with role `pilot` carries no paperwork. The demo pilot pair (John Cena / Mark Cuban on NM/AZ trips, `src/lib/demo/pilot-cars.ts`) is an overlay and is not linked to `DEMO_PILOT_DRIVERS` / `DEMO_PILOT_COMPANY`.
- **Plans:** four plans Free / Starter / Pro / Fleet in `src/lib/demo/credits.ts` (demo, `CURRENT_PLAN = Free`) and `PlanName` in `src/lib/domain/invoicing.ts` with `canUseBusinessTools(plan)` = Pro or Fleet. The plan model is the same for every account type (Nash, 2026-09-12: "plans same across users"). **There is no carrier-specific plan anywhere in the code** — the Billing page (`/billing`) shows the demo Free plan for whoever is signed in; the only plan switches are the pilot owner/driver preview switches in `src/lib/demo/invoicing-store.ts` (`useOwnerPlanPreview`, `useDriverPlanPreview`).
- **Locked-feature pattern exists:** `src/components/app/pilot-tools/locked-pro.tsx` (`LockedProFeature`) — "visible but locked", dashed amber card, `Upgrade to Pro` → `/billing`, `Not now`. Copy in `LOCKED_PRO_COPY` (`src/lib/domain/invoicing.ts`). Built for the pilot's invoice/expense tools; reusable.

---

## Task list (Phase 1 replica — demo data, no backend, admin can preview both states)

### Module A — Carrier plan (needed before anything can be gated)

**Task A1 — Carrier plan in the replica.** Add a carrier plan value (same `PlanName` ladder) with a preview switch so the design can be seen in both states: `carrierPlan` in the demo preview store (sessionStorage, same pattern as `useOwnerPlanPreview`), default **Free**. Expose the switch where the carrier's plan is already visible — the Billing page for a carrier session and the pilot testing bar / dev preview (admin only). *Not yet implemented.*

**Task A2 — "Pro" rule.** `carrierCanSeePilotPaperwork(plan)` = Pro (and Fleet, if Q2 says yes) in `src/lib/domain/invoicing.ts` next to `canUseBusinessTools`, with a unit test. *Not yet implemented.*

### Module B — Paperwork in the carrier's My Pilot tab (P1, P2)

**Task B1 — Paperwork section per pilot entry.** In `MyPilotTab` (carrier viewer only, gated by a new prop such as `paperwork: 'shown' | 'locked' | 'hidden'`), each pilot entry (pilot dispatch and pilot driver) gets a **Paperwork** block listing that party's documents: label, status pill (Approved / Uploaded / Expiring Soon / Expired / Not Uploaded), expiration date, and a `View` action (placeholder in the replica: opens the stored upload marker or shows "file preview arrives with the documents backend"). Company documents for the dispatch entry, driver documents for the driver entry. *Not yet implemented.*

**Task B2 — Data for the entries.** Extend `MyPilotEntry` with `documents?: { key, label, status, expirationDate? }[]`.
- Pilot shell preview (`CarrierSidePreview`): from `DEMO_PILOT_COMPANY` / `DEMO_PILOT_DRIVERS` (with the sessionStorage upload overrides so an upload on the pilot side shows on the carrier side).
- Real carrier trip view (`MyPilotWorkspaceTab`): demo pilot pair → map John Cena to a demo driver document set and Mark Cuban to the demo company document set (design preview only); real pilot participants → "No paperwork on file yet" until pilot accounts exist. *Not yet implemented.*

**Task B3 — Carrier Dispatch Trip View sets the option.** `carrier-trip-view.tsx` passes the carrier plan into the shell; the shell resolves `paperwork` = shown (Pro) / locked (Free, Starter) for the carrier viewer. Broker viewer stays `hidden` — the broker's My Pilot tab does not change. *Not yet implemented.*

### Module C — Upgrade incentive (P3, P4)

**Task C1 — Locked state.** For a non-Pro carrier, the Paperwork block is replaced by one incentive card (one per tab, not one per pilot) in the `LockedProFeature` style: title, one-line pitch, `Upgrade to Pro` → `/billing`, `Not now` (collapses to a one-line link). Copy to confirm (Q4); proposal:
- Title: **Pilot paperwork — Pro feature**
- Text: *Pro carriers see every pilot's certificate of insurance, certifications and licenses right here on the trip — with expiration dates — so you know the escort is covered before the load moves.*
*Not yet implemented.*

**Task C2 — Plan page mention.** Add "View pilot car paperwork on your trips" to the Pro plan's `includes` list in `src/lib/demo/credits.ts` so the Billing page advertises the same benefit. *Not yet implemented — only if Q5 says yes.*

### Module D — Verification

- Render test for both states (Pro → documents listed; Free → incentive card, no document names in the markup).
- Dev preview check on phone and desktop: `/dev-preview/cd/trip` with the plan switch, and `/admin/pilot-preview/HH-2041?as=carrier`.
- Record the outcome here and in `PILOT-PRO-TOOLS-INVOICING-TASKS-2026-09-12.md` (Module B entitlement rules).

---

## Client answers (2026-09-13, voice note)

1. **Which documents does a Pro carrier see?** All of the pilot's documents, or a fixed set? The W-9 carries the pilot's tax ID — include it, or show only COI, licenses and certifications (and the business license for the dispatch)?
2. **Does Fleet count as Pro** for this rule, as it does for the invoice/expense tools?
3. **Status only, or the file itself?** Status + expiration date (what the replica can show today), or must Pro carriers open the actual COI / license file? (Real files need the documents backend; the replica can only show a placeholder "View".)
4. **Incentive copy** — is the proposed text in Task C1 right, or do you want your own wording?
5. **Advertise on the plan page too** (Task C2), or keep the incentive inside the trip only?
6. **Both pilot parties?** Paperwork for the pilot dispatch (company documents) **and** the pilot driver (driver documents), or only the driver who is physically on the load?
7. **Expired or missing paperwork** — plain status pills, or should the carrier also get a warning line on the entry ("COI expired 08-31") like the pilot dashboard's readiness labels?

1. **Everything** — COI, license, certificates, all of it, each with a PDF icon to click. (W-9 included.)
2. **Fleet counts** — "Pro or higher".
3. PDF icon per document. Invoices are visible **regardless of plan** — "if the invoice was created and sent to them, they will see it".
4. Proposed incentive copy approved.
5. Yes — advertise on the plan page.
6. Both the pilot driver **and** the pilot dispatch.
7. Yes — alert on missing paperwork.
8. **New:** "For now this feature will be open for everyone… when the time comes we can prepare everything to have that feature only for Pro users." (A 90-day free window was floated, then set aside.)

## Implemented (2026-09-13) — Phase 1 replica

| Task | Status | Where |
|---|---|---|
| A1 carrier plan preview switch | Done — `useCarrierPlanPreview` (sessionStorage, default Free) + `usePaperworkGatePreview` ('open' = today, 'pro' = future) | `src/lib/demo/invoicing-store.ts`; switch UI `PaperworkPreviewSwitch` (admin only, shown above the tab) |
| A2 "Pro or higher" rule + open-to-all flag | Done — `carrierCanSeePilotPaperwork(plan, openToAll)`, `PILOT_PAPERWORK_OPEN_TO_ALL = true`. **Flip to `false` to start the Pro-only period.** | `src/lib/domain/invoicing.ts` |
| B1 paperwork block per pilot entry (PDF icon, status pill, expiration) | Done — `PaperworkBlock` in `MyPilotTab`; `paperworkList()` fills every slot of the account type | `src/components/app/pilot-tools/my-pilot-tab.tsx`, `src/lib/domain/pilot.ts` |
| B2 data | Done — pilot-preview carrier view: company docs (with pilot-side uploads) + driver docs; real carrier trip view: John Cena / Mark Cuban demo paperwork (`demoPilotPaperwork`), real pilots "No paperwork on file yet" | `pilot-assignment-workspace.tsx` (`CarrierSidePreview`), `trip-workspace.tsx` (`MyPilotWorkspaceTab`), `src/lib/demo/pilot-cars.ts` |
| B3 carrier only | Done — `paperwork` prop set only for the carrier viewer; broker tab unchanged | same |
| PDF on click | Done — `buildPaperworkPdf` (pdf-lib) carries the document record until the documents backend serves the upload | `src/lib/demo/invoice-pdf.ts` |
| Missing-paperwork alert | Done — `paperworkAlerts()`: required docs missing / rejected / expired / expiring soon, red line above the list | `src/lib/domain/pilot.ts` |
| C1 locked card | Done — `LockedProFeature feature="paperwork"` with the approved copy; only renders when the gate is on and the plan is Free/Starter | `src/components/app/pilot-tools/locked-pro.tsx` |
| C2 plan page | Done — Pro and Fleet `includes`: "View pilot car paperwork on your trips (COI, licenses, certifications)" | `src/lib/demo/credits.ts` |
| Invoices regardless of plan | Already true — the carrier's invoice list is not gated by plan; unchanged | `my-pilot-tab.tsx` |
| D verification | tsc clean; eslint clean on touched files; vitest 144 pass (+ pre-existing warnings failure); tests `tests/invoicing.test.ts` (rule, alerts, plan copy) and `tests/pilot-render.test.tsx` (open state, locked state, broker untouched); browser: `/dev-preview/cd/trip` → My Pilot shows both pilots' paperwork with the alert on the dispatch; gate 'pro' + Starter → incentive card; Pro → paperwork | — |

---

## Revision (2026-09-13, second voice note) — Starter, 90-day free window, brokers + carriers + drivers

> "Maybe this feature should be part of our Starter package. Everyone that signs up will have this feature unlocked for ninety days for free even if they don't have any membership. If they are Starter package or higher, they all get this feature… it's beneficial for brokers and carriers to have access and history to the pilot paperwork… make sure they understand this is focused for brokers and carriers — carrier dispatchers and the drivers — to have a way to track the paperwork for each pilot assigned to a trip."

Requirements extracted:

| # | Requirement | Done |
|---|---|---|
| R1 | Plan rule: **Starter or higher** includes pilot paperwork (Pro/Fleet included). | `pilotPaperworkAccess()` → `included` for Starter/Pro/Fleet |
| R2 | **Free accounts**: unlocked for **90 days from sign-up**, then locked with the upgrade incentive (now "Upgrade to Starter"). | `trial` with days left from the profile's `created_at` (`PAPERWORK_TRIAL_DAYS = 90`); `locked` after; the earlier open-to-all flag is removed |
| R3 | Audience: **brokers and carriers** — the freight broker trip view, the carrier dispatch trip view **and the carrier driver app**. | Broker My Pilot tab now shows paperwork (contact-hiding rule for dispatcher-hired pilots unchanged); carrier driver: paperwork block under each pilot's contact card on the state cards (`PilotPaperwork` in `driver-view.tsx`) |
| R4 | Users must understand the purpose. | Purpose line on the tab: "Built for brokers, carrier dispatchers and drivers: track the paperwork of every pilot assigned to this trip." + "Free for your first 90 days · N days left" / "Included in your plan" |
| R5 | Plan page. | Free: "Pilot paperwork on your trips - free for your first 90 days"; Starter: "Pilot paperwork on your trips (COI, licenses, certifications) - for brokers, carrier dispatchers and drivers"; Pro/Fleet line kept |

Files: `src/lib/domain/invoicing.ts` (`pilotPaperworkAccess`, `PAPERWORK_PURPOSE`, `PAPERWORK_LOCKED_COPY`), `src/lib/demo/invoicing-store.ts` (`useViewerPlanPreview`, `useSignupAgePreview`), `src/components/app/pilot-tools/my-pilot-tab.tsx` (`useViewerPaperworkAccess`, exported `PaperworkBlock`, preview switch "Your plan / Signed up N days ago"), `trip-workspace.tsx` + fb/cd pages (`myAccountCreatedAt`), `ct-dashboard/driver-view.tsx` + ct pages (`accountCreatedAt`), `pilot-assignment-workspace.tsx` (carrier and broker preview), `credits.ts`, tests.

Verified: tsc clean; eslint clean on touched files (the driver-view set-state-in-effect error is pre-existing); vitest 147 pass + the pre-existing warnings failure; browser `/dev-preview/cd/trip` → My Pilot shows the purpose line, "Free for your first 90 days · 78 days left" and the paperwork; with sign-up set to 200 days ago the "Pilot paperwork - Starter Feature" card with Upgrade to Starter appears. The carrier driver page needs a sign-in, so it is covered by typecheck only.

Not built (say if wanted): a separate paperwork **history** log (uploads/expirations over time). Today "history" = the upload and expiration dates on each document.
