# Pilot Company & Pilot Driver Management — Task Document

Source: "HeavyHaul Agent Pilot Company and Pilot Driver Management Logic" (implementation article, received 2026-09-12).
Scope: the article's **MVP list (section 62)** plus the rules that MVP items depend on. Section 63 "Future Improvements" is explicitly **out of scope** and is not tasked here.

## Current state (verified in codebase)

| Area | Today | Gap |
|---|---|---|
| Account roles | `broker / dispatcher / driver / admin` (`src/types/db.ts`, `AUTH_USERS`, `auth_accounts.role` check) | No `pilot_driver` / `pilot_company` account role |
| Trip roles | `trip_role` enum already includes `pilot` (`0001_init.sql`) | Exists, but a pilot participant sees the full broker/dispatcher workspace with every document |
| Trip access | All-or-nothing per trip via `trip_participants` (`src/lib/data/trips.ts`) | No state / permit / full-trip scoping |
| Rate confirmation | `documents.kind = 'rate_confirmation'`, signed URL for every participant | No role-based hiding anywhere |
| Signup | No self-signup; `/signup` only creates `early_access_signups`; accounts created by admin | Pilot signup flow does not exist |
| Email verification | None for user accounts (only company-claim tokens) | Needed |
| Email sending | No provider wired; templates exist in `src/lib/email-templates.ts`, invite links are copied manually | Needed for pilot emails |
| Companies | `company_type` = `broker / carrier` only; no company documents | No pilot company, no insurance/W-9/business license |
| Vehicles | Only per-trip `trip_units`; no fleet table, no photos | Pilot vehicle records + 4 photos missing |
| Documents | `documents` table has no status/expiration/owner; only trip documents | Pilot document system missing |
| Contacts | `carrier_contacts.role` = `driver / broker` | No pilot contact type |
| AI chat | Context = full trip + all permits, no role filtering (`api/trips/[id]/chat/route.ts`) | Scoping by pilot access missing |
| Room chat | One `chat_messages` room per trip, all participants | No scoped pilot assignment chat |
| Route ordering | Any participant may order (`canRequestServices`) | Already available to pilot participants |
| Activity log | `trip_events` + History tab | Pilot-specific events missing |
| Capabilities | Nothing (lead/chase/high pole only appear as text) | Missing |

## Decisions from client (2026-09-12)

1. **Self-signup: yes.** HeavyHaul Agent will have a self-signup module and interface for pilot users in the app.
2. **Phase 1 is a front-end replica, admin-only.** For now: no real email sending, no real credentials/login created. Build a front-end "pilot test" of the account creation flow showing how it looks, which steps are required, and which fields are required. Like all existing test tooling, it is visible to **admin users only** (gate on `user.internal`, same as the role switcher and design previews).
3. **Email integration and real account creation come later**, in a separate discussion. Status today: **the account creation module is not finalized.** There is no self-signup; `/signup` only writes to `early_access_signups`, and accounts are created by admin through `AUTH_USERS` or the admin user console (`/admin/users`). Building real pilot account creation will require that module first.

4. **Phase 1 scope (second answer, same day):** "We're gonna create all the tools, the replica… the whole onboarding steps, how to create an account… this is gonna live with the existing design. We're gonna just add the dashboard for pilot dispatch and the dashboard for the pilot driver interface. And that's it… pilot driver interface, it's the same as the carrier driver with an extra tab or something." So Phase 1 = signup/onboarding replica + Pilot Dispatch dashboard + Pilot Driver interface, inside the existing app shell and preview tooling.

5. **Onboarding feedback (2026-09-12, after the first replica):** signup is **three steps only** — account type, details (name, email, phone, independent or company), validate email — and "once I validate my email, it should let me go directly into the pilot dashboard." Steps 4–7 (documents, vehicle, capabilities, summary) are done **after login**: shown on My Assignments as unfinished tasks ("step four, what I need to do, step five…"). With an assigned trip and steps still open, the pilot can still view the shared permits, and a reminder sits "somewhere on top, above the states that are shared with me." Documents: an independent driver uploads their own; a driver who named a pilot company gets those documents handled by that company once the relationship is approved, and can also upload them himself; vehicle and capabilities always stay with the driver. A carrier dispatcher can never upload to a driver's profile ("No. This is my personal.").

6. **Invite access + pilot workspace feedback (2026-09-12, third round):**
   - Carrier dispatch, when inviting a pilot from the trip workspace, must choose the pilot's access for that trip: all states, select certain states, select certain permits, or "decide later" — and can send the invitation with "decide later". **Built in the real invite form** (`trip-workspace.tsx` InviteForm → `PilotAccessChooser`); the choice is recorded in the trip History as `pilot access: …`. Per-scope enforcement stays Phase 2 (Module F).
   - What the pilot sees on opening: nothing shared → no permits; one permit → that permit only; one state → that state only.
   - **Access replication:** whoever a pilot adds to the trip inherits exactly the pilot's access. A pilot dispatch adds pilot drivers; a pilot driver can add only a pilot dispatch. Both see the same single state/permit.
   - **Pilot trip workspace** replica added at `/trips/pilot-preview/[assignment]` (`?as=driver` for the driver), mirroring the three-column workspace; opened from "Open trip" in the dispatch assignments table and from the driver's Active Assignment.
   - **Documents gate (pilot dispatch only):** without certificate of insurance, W-9 and business license on file, the dispatch cannot open the trip workspace; an alert lists what is missing and sends them to Documents. Note: this makes the business license a hard requirement for opening trip info, which is stricter than the article's 30-day grace (§11) — the grace window still applies to the account flag/readiness label only. Confirm for Phase 2.
   - **Broker missing from the pilot testing bar:** not a code regression. The bar lists only roles that have a configured test account, and on 2026-09-11 the only broker account (`Nash_Turcan`) was changed to admin, so no account carries the broker role. Fix: add a broker entry to `AUTH_USERS` in `.env` (shape in `.env.example`) and restart the dev server.

7. **Pilot driver panes + testing bar (2026-09-12, fourth round):**
   - "My vehicle should be in the profile docs… merged both in one." → the pilot driver's own pane is now **My Pilot Car** (profile, documents, my vehicle, capabilities, pilot companies).
   - The freed pane is **Carrier Info** for the current assignment: carrier, carrier dispatcher and carrier driver (name, phone, email, call/email), truck, trailer, commodity, overall dimensions, weight. Shown on every assignment regardless of permit scope, "for creating invoices and record keeping". Phase 2 note: this is broader than article §20 (carrier contacts "depending on scope") — the client wants it always.
   - Pilot testing bar regrouped as **Broker · Carrier (Dispatcher, Driver) · Pilot Car (Signup, Dispatch, Driver, Trip workspace) · Admin**. A role with a test account switches the real session; Broker has none since 2026-09-11, so it falls back to the `?view=broker` layout preview (hover hint says so). Adding a broker entry to `AUTH_USERS` upgrades it to a real switch automatically.

8. **Per-state links + truck/trailer identification (2026-09-12, fifth round):**
   - On the carrier driver's Active Trip and the pilot driver's Active Assignment, each state's permit shows three small links: **View permit · View provisions · View state notes**. State notes are the internal state knowledge the team shares with drivers (same content as the trip workspace's state-info panel; sample data until the state-data backend connects). Built for both drivers; the shared dialog lives in `src/components/app/state-notes-dialog.tsx`.
   - Pilot driver Carrier Info now shows, for truck and trailer: year, make, model, unit number, VIN, plate number and registration state ("important for him for legal purposes… find the information who owns that truck and trailer and go get his payment"). Phase 2: this maps to the existing per-trip `trip_units` record (truck/trailer VIN, make, model, year already exist there; **plate number and plate state do not** — add them in Module G).

9. **Pro tools / invoicing (2026-09-12):** see `PILOT-PRO-TOOLS-INVOICING-TASKS-2026-09-12.md`. Adds the "My Pilot" tab (pilot dispatch workspace, real carrier/broker workspace), Invoices & expenses in the driver's My Pilot Car pane, and the Agent pane rebuilt on the carrier driver's ChatPanel (voice, languages, sharing choice, shared-states-only selector).

10. **Broker trip view (2026-09-12):** section 3 · Docs permit cards had View permit and View provisions; **View state notes** added as the third link (opens the existing state-info panel / dialog). Shared permit card, so the carrier workspace gets it too.

11. **Carrier driver · My Unit (2026-09-12):** truck and trailer cards now show **Plate #** and **Registration state**. Values are placeholders until pulled from the orders — Washington for the truck, Maine for the trailer, generic plate numbers. Phase 2: add `truck_plate`, `truck_plate_state`, `trailer_plate`, `trailer_plate_state` to `trip_units` and source them from the Synchron order (same fields the pilot driver's Carrier Info needs, decision 8).

12. **Pilot dispatch dashboard menu (2026-09-12):** the eleven-item tab strip was too long ("he needs to scroll left and right… this page is about the assignments"). Now: a **management menu above the alert tiles** (Assignments · Pilot Drivers · Vehicles / Units · Documents · Contacts · Company Profile · Settings · Billing / Plan) and, under the tiles, a tab strip with only the four assignment views. Both rows wrap; no horizontal scrolling. Opening a management section replaces the assignment tabs with a section heading and a "Back to assignments" link.

13. **Admin bypass on the documents gate (2026-09-12):** the pilot dispatch documents-required screen keeps Upload documents / Back to assignments and, for internal admins only, adds **Admin bypass →** which opens the pilot dispatch trip info directly. The workspace then shows an amber note listing what is still missing, so the bypass is visible and a real pilot dispatch is unaffected.

14. **Pilot driver · Carrier Info truck/trailer cards (2026-09-12):** order is now Unit number → year make model → VIN → Plate (state + number). The separate "Registration state" line was removed because the state is already in front of the plate number.

15. **Carrier driver · pilot cars on the state cards (2026-09-12):** in Active Trip, a state whose pilot access covers it shows "✓ Pilot car attached" next to the permit's validity mark, and under the route a "Pilot car(s) for <state>" list: tap a pilot to open name, phone (tap to call), email (tap to email) and a Copy button. Built on real data — pilot participants plus the access recorded on their invitation in trip History. Pilot participants carry one trip role today, so each entry reads "Pilot car"; the pilot-driver vs pilot-dispatch labels arrive with pilot accounts (Phase 2).

16. **Pilot dispatch · Billing / Plan and Settings tabs (2026-09-12):** both tabs now render the real pages inline instead of linking out. Billing / Plan = the full Billing & Wallet view (current plan and usage, payment method with Add card, Free / Starter / Pro / Fleet plan cards with details and Upgrade, pay-as-you-go and Extended Route pricing, route purchase history, invoices placeholder). Settings = the settings form (notifications, agent languages). Same data loaders as /billing and /settings (`loadRoutePurchases` extracted to `src/lib/data/billing.ts` so both pages share it).

17. **Demo pilot car on New Mexico / Arizona (2026-09-12):** every existing trip with an NM or AZ permit shows a hired pilot car on those states — **John Cena** (pilot driver, (505) 555-0147, john.cena@pilotcars.example) and **Mark Cuban** (pilot dispatch, (602) 555-0199, mark.cuban@pilotdispatch.example). Implemented as a demo overlay (`src/lib/demo/pilot-cars.ts`, same pattern as the demo current state), not as database rows: the carrier driver's NM/AZ state cards get the "Pilot car attached" mark and the tap-to-contact cards, and the carrier/broker "My Pilot" tab lists the pair with access "States: NM, AZ". A real pilot participant on the trip replaces the demo pair.

18. **Pilot dispatch trip view parity (2026-09-13):** section 3 · Overview now uses the same permit card as the freight broker trip view — state name (opens state notes), permit number and dates, route chip with formats open by default, the W · H · L · GVW row cross-checked against an **Overall dimensions** block above the permits, then **Ask about this permit · View permit · View provisions · View state notes**. Section 2 is the same Agent chat as the broker/carrier trip view (type, tap-to-talk, languages, share-my-questions), limited to the shared states; "Ask about this permit" focuses it on that permit. Applies to the pilot driver assignment view too (same shell).

19. **Pilot driver · route formats on Active Assignment (2026-09-13):** a shared permit whose route is ready now shows the delivered formats — Google Maps parts, GPX file, Hummer GPS — as links, open by default under the "✓ Route ready" chip (which hides/shows them). Same shared component as the pilot workspace (`pilot-tools/route-status-line.tsx`); demo links until the pilot backend.

20. **Pilot driver adds people to the trip (2026-09-13):** on Active Assignment, **Add my pilot dispatch** opens a list of the driver's active (approved) dispatchers to pick from, or an email field to invite one; **Add another pilot** (new — supersedes the earlier "a pilot driver can add only a dispatch") lists pilots linked through the driver's companies, or takes an email. Both get exactly the driver's access. An invitee without an account gets an email to create it (three-step signup) and join the trip. Two admin-manageable templates were added under Email Templates: **Pilot Dispatch Invited to Trip** and **Additional Pilot Invited to Trip** (variables: pilot driver name/phone, invitee name, trip, shared access, workspace link, signup link). No email is sent in this phase.

21. **One trip on all three dashboards + broker's pilot visibility (2026-09-13):** the real trip **HH-95595781** (Brawley, CA → Terlingua, TX · ATLAS LOGISTICS GROUP INC · CA, AZ, NM, TX) is on the freight broker and carrier dashboards (real data) and now also on the pilot dispatch dashboard as a mirrored demo assignment: John Cena (new ABC Pilot Cars driver, unit JC-1) hired for **New Mexico** by the carrier dispatcher, route ready. Dashboards show a "🚗 Pilot car · NM, AZ" reference on trips whose states carry the pilot (carrier rows also name John Cena / Mark Cuban). **Broker rule:** a pilot hired by the dispatcher shows to the broker as attached (name, state) **without phone/email** — "Hired by the carrier dispatcher — contact details stay with the carrier"; contact details show only for a pilot the broker invited. Applied in the real workspace "My Pilot" tab and the design preview.

Consequence: Phase 1 is Tasks P1–P3 below (**done 2026-09-12, updated for decisions 5–21**). The backend/data tasks in Modules C–J remain the specification for the later phase and are unchanged.

---

## Phase 1 — Admin-only front-end prototype — ✅ DONE 2026-09-12

Where it lives (all gated on the session's `internal` flag, like the role bar and design previews):
- `/signup/pilot` — onboarding replica (`src/app/(auth)/signup/pilot/`)
- `/dashboard?view=pilot-dispatch` — Pilot Dispatch dashboard (`src/app/dashboard/pilot-company-dashboard.tsx`)
- `/dashboard?view=pilot-driver` — Pilot Driver interface (`src/app/dashboard/pilot-driver-view.tsx`)
- Entry points: "Pilot car preview" links on the pilot testing bar, the dashboard view switcher, and the user menu's Admin group.
- Rules and labels: `src/lib/domain/pilot.ts` (document slots, capabilities, readiness, rate-confirmation rule). Demo data: `src/lib/demo/pilot.ts`. Tests: `tests/pilot.test.ts`, `tests/pilot-render.test.tsx`.

### Task P1 — Pilot signup & onboarding replica (front end only, admin-gated) — ✅ done (revised per decision 5)
**Current behaviour:** three steps (account type → details → validate email), then a "Go to my dashboard" link that opens the pilot driver or pilot dispatch preview in its just-signed-up state (`&onboarding=new`). Steps 4–6 below are no longer in the wizard; they live in the dashboards as an "Unfinished setup" card (My Assignments / assignments tab), a "Finish your setup" reminder above the shared states on an assignment, and in-place upload / add-vehicle / capability toggles. The original step list is kept below for the record.
- Location: a new route reachable only when `user.internal` is true (non-admin → redirect to `/dashboard`, same pattern as `/admin/*`). Add a link in the existing admin/preview tooling so admins can find it.
- No backend writes, no emails, no login credentials. State lives in the browser only (component state / localStorage), and the prototype must clearly label itself as a test preview.
- Screens and steps, in this order, matching article §6–§12 and §56:
  1. "Are you signing up as a Pilot Driver or a Pilot Company?" (two options).
  2. Pilot Driver branch: "Do you work under a pilot company?" → independent, or company-connected with fields pilot company name, company phone (if known), company email (if known), dispatcher name (if known). Show that this creates a *pending* relationship request, not a verified link.
  3. Pilot Company branch: company name, company address, company phone, company email, main contact / dispatcher name.
  4. Email validation step (simulated: show the "check your email" state and a button that marks it validated). Explain that shared permits are not viewable until validated.
  5. Required documents step. Pilot Driver: W-9, driver license, certificate of insurance, pilot car / escort certification, state certifications (if available), plus optional slots labelled "Optional State Certification", "Utah Certification, if applicable", "Washington Certification, if applicable". Pilot Company: certificate of insurance, W-9, business license (with the 30-day grace note), optional certificate of good standing, optional company documents. Uploads are simulated (file picked, shown as "Uploaded", nothing stored).
  6. Vehicle / unit creation with the Task D1 fields and the four required photo slots (Front, Back, Left, Right).
  7. Capability toggles (Task D4 list) with status "Self-declared".
  8. Summary / readiness status screen (Task B3 labels) showing which required fields are complete and what is still missing, and the rule that permits stay hidden until onboarding is complete.
- Mark required vs optional fields exactly as in the article; do not invent extra fields.
- Reuse existing form components and app shell styling; do not redesign existing pages.

### Task P2 — Pilot Dispatch dashboard replica — ✅ done
Mirrors the carrier dispatch dashboard (header, summary tiles, tab strip, table) with the article's §38 tabs: All / Active / Pending Assignments, Completed / History, Pilot Drivers, Vehicles / Units, Documents, Contacts, Company Profile, Settings, Billing / Plan. Demo data. Includes: assignment detail with shared scope, permits visible vs. locked, assign approved driver / unit / position, accept → in progress → completed, notify carrier, activity log; relationship requests with Approve / Deny / Request more info and a relationship log; vehicles with the four photo slots, add unit, assign driver, mark inactive; company documents with statuses and the 30-day business license countdown; company profile per §37. Settings and Billing / Plan link to the existing pages.

### Task P3 — Pilot Driver interface replica — ✅ done
Same phone frame, header, swipe track and bottom nav as the carrier driver view, with the panes My Assignments, Active Assignment, Agent, My Vehicle, plus the extra **Profile & Docs** pane. Active Assignment shows one section per shared state with permit, curfew, escort, permit file, ask agent and route order/ready, a "Not shared with you" card for permits outside the scope, the trip overview only on full-trip access, the scoped pilot assignment chat, and the "hidden from pilot accounts" note. Agent pane shows a scoped conversation including the refusal on the rate confirmation and on an unshared state.

**Rule change recorded from decision 5 (flag for Phase 2):** the article (§12) hides shared permits until required documents are uploaded; Nash's feedback says the pilot "could probably view them" with the reminder on top. The replica follows the feedback. Confirm which rule the backend should enforce.

**Not built in Phase 1 (not named in the 2026-09-12 answer):** the carrier-side "Manage Pilot Access" panel inside the trip workspace (Task F1/F6), the broker and carrier views of a pilot assignment (Tasks G2/G3), the admin view (G4), and any email template. These are Phase 2 unless you want them mocked too.

---

## Phase 2 — Full implementation (specification)

## Module A — Roles, Accounts, Signup, Email Validation

### Task A1 — Add pilot account roles
- Add two account roles: `pilot_driver` and `pilot_company`.
- Update everywhere the account role enum is defined or checked: `UserRole` in `src/types/db.ts`, `public.user_role` enum, `auth_accounts.role` check constraint (`0015_auth_accounts.sql`), `AUTH_USERS` parsing in `src/lib/auth/env-users.ts`, admin user console role dropdown (`src/app/admin/users`), `dashboardRole` in `src/lib/role-view.ts`.
- Article rule: these are "different account types with different dashboards and responsibilities".
- Do not remove or rename the existing `pilot` **trip** role; that remains the participant role for any pilot user on a trip.

### Task A2 — Pilot signup flow (self-service)
Article sections 6–8. Note the codebase currently has **no self-signup at all** (see Open Question 1 before starting).
- First question: "Are you signing up as a Pilot Driver or a Pilot Company?" Options: Pilot Driver / Pilot Company. This choice controls the rest of onboarding.
- **Pilot Driver branch**: ask "Do you work under a pilot company?" Options: "I am independent / self-employed" / "I work with a pilot company".
  - Independent → continue as individual pilot driver.
  - Works with a company → collect: pilot company name, company phone (if known), company email (if known), dispatcher name (if known). This **does not** verify anything; it creates a **pending relationship request** (see Task E2).
  - Then the driver completes profile and uploads required documents (Task C1).
- **Pilot Company branch**: collect company name, company address, company phone number, company email, main contact / dispatcher name, then email validation, then document uploads: certificate of insurance, W-9, business license, optional certificate of good standing, optional company documents (Task C2). The result must be a **company profile**, not just a personal profile.
- Signup screen also includes (article §56): vehicle/unit creation (Task D1), capability toggles (Task D4), company relationship request (Task E2).

### Task A3 — Email validation
- Both pilot drivers and pilot companies must validate their email address.
- Rule: a pilot user may create an account and start onboarding, but **must not receive active permit access / view shared permits until email is validated**.
- Store `email_verified` on the pilot profile (article data object §55).
- Log "Email validated" in the activity log (Task I1).
- Requires an email sender (Open Question 2).

### Task A4 — Onboarding gate before viewing shared permits
Article §12. Enforce server-side; the pilot cannot see shared permits until all of the following are true:
- Validated email
- Name
- Phone number
- Account type chosen
- Insurance uploaded
- W-9 uploaded
- Driver license uploaded (pilot drivers)
- Business license uploaded (pilot companies) **or** inside the 30-day grace window (Task C3)
- Pilot accepted the assignment
When an invited pilot has no account yet, the invite link leads to onboarding with these steps in order: create account → choose Pilot Driver / Pilot Company → validate email → upload required documents → accept assignment → receive access to shared scope. This is the "Pilot Invite Acceptance Screen" (§56).

---

## Module B — Pilot Profiles

### Task B1 — Pilot Driver profile
Fields (§36): full name, email, phone, home base, years of experience, states served, service radius, capabilities (Task D4), certifications, insurance status, W-9 status, driver license status, linked pilot companies, linked vehicles, assignment history, completion history, internal notes (admin-only), carrier-visible notes (if allowed).
Data object (§55) `pilot_driver_profile`: `user_id, years_experience, home_base, service_states, capabilities, document_status, readiness_status`.
Pilot Profile screen tabs (§56): Profile, Documents, Vehicles / Units, Capabilities, Company Relationships, Assignments, Settings.

### Task B2 — Pilot Company profile
Fields (§37): company name, address, phone, email, main contact, certificate of insurance status, W-9 status, business license status, certificate of good standing status (optional), pilot drivers, pilot vehicles, assignments, service states, capabilities, company notes, verification status.
Data object (§55) `pilot_company_profile`: `company_name, address, phone, email, insurance_status, business_license_status, w9_status, verification_status, created_at`.
Existing `companies` table only allows `broker|carrier`; decide whether to extend it or create a separate table (Open Question 3).

### Task B3 — Pilot readiness status
Article §60. Show a single readiness label computed from profile + document state. Values listed in the article: Incomplete Profile, Email Not Verified, Documents Missing, Insurance Missing, Business License Due in N Days, Ready for Assignment, Verified Pilot, Expired Documents, Admin Review Required.
Shown to carriers before sharing permit access (Task F1 "See pilot verification status") and stored as `readiness_status` on the driver profile.

---

## Module C — Pilot Documents

### Task C1 — Pilot driver required documents
Required upload slots: W-9, driver license, certificate of insurance, pilot car / escort certification, state-specific pilot certifications (if available).
Optional slots labelled exactly: "Optional State Certification", "Utah Certification, if applicable", "Washington Certification, if applicable". The UI **must not** claim any state certification is mandatory.

### Task C2 — Pilot company required documents
Required: certificate of insurance, W-9, business license. Optional: certificate of good standing, company operating documents, state-specific company certifications.

### Task C3 — 30-day business license rule (pilot companies)
- Company can create account and onboard without a business license, but must upload it within 30 days of account creation.
- After 30 days without it, flag the account with: "Business License Missing", "Verification Incomplete", "Limited Access", "Admin Review Required".
- Readiness status shows "Business License Due in N Days" during the window (§60).

### Task C4 — Pilot document storage and status
Data object (§55) `pilot_documents`: `owner_type (pilot_driver|pilot_company), owner_id, document_type, file_storage_key, status, expiration_date, uploaded_at, reviewed_by, reviewed_at`.
Statuses (§59): Not Uploaded, Uploaded, Pending Review, Approved, Rejected, Expired, Expiring Soon.
- Track expiration dates for insurance, license, certifications. W-9 has no expiration; track upload date only.
- Storage: use a new **private** Supabase bucket (pattern of `company-verification-docs`); signed URLs on read like `trip-documents`.
- Who sets Approved/Rejected: see Open Question 4.

### Task C5 — Pilot document visibility rules (backend-enforced)
Article §13, §14, §47, §48. Pilot documents are never public.
| Viewer | Can see pilot documents? |
|---|---|
| Carrier dispatcher | Yes, for pilots connected to their trip |
| Carrier company admin | Yes, for pilots on their company's trips |
| Internal admin | Yes, all |
| Pilot company | Yes, for its own **approved** drivers |
| Pilot driver | Own documents only (view + manage) |
| Broker | **No** files at all. Sees profile/contact info only (Task G2) |
Also log "Carrier viewed pilot documents" (Task I1).

---

## Module D — Pilot Vehicles / Units and Capabilities

### Task D1 — Pilot vehicle record ("My Cars" / "My Units")
Both pilot drivers and pilot companies get a vehicle section. Fields (§32): nickname/unit number, year, make, model, color, license plate, plate state, VIN (optional), insurance linked to vehicle (if applicable), assigned driver, owner (pilot driver or pilot company), status active/inactive, equipment type, notes.
Data object (§55) `pilot_vehicle`: `owner_type, owner_id, unit_number, year, make, model, color, plate_number, plate_state, vin_optional, status, assigned_driver_id`.
Ownership must be explicit when a driver works with multiple companies.
This is separate from the existing per-trip `trip_units` table; do not reuse it.

### Task D2 — Four required vehicle photos
Each unit requires exactly four photos: Front, Back, Left side, Right side. Data object `pilot_vehicle_photos`: `pilot_vehicle_id, photo_type (front|back|left|right), file_storage_key, uploaded_at`.
Vehicle photos **are** visible to brokers when the pilot is assigned to a trip (unlike paperwork).

### Task D3 — Vehicle actions
- Pilot company: add vehicle, upload photos, edit info, assign vehicle to pilot driver, remove vehicle from driver, replace vehicle for an assignment, mark inactive, link vehicle to current assignment, view vehicle assignment history.
- Pilot driver: add personal vehicle, upload photos, edit details, link vehicle to assignment, mark inactive, manage vehicle profile.
- Log "Vehicle added", "Vehicle photos uploaded", "Pilot driver assigned vehicle" (Task I1).

### Task D4 — Capability toggles
For pilot drivers and pilot companies. Toggles (§35): Lead pilot, Chase / rear pilot, High pole, Steer / tillerman support, Route survey, Bucket / utility coordination (if applicable), Police escort coordination (if applicable), Oversize escort, Superload escort, Night movement support (if applicable), Local city escort support.
Each capability has a status: Self-declared, Document uploaded, Verified by admin, Expired, Rejected.

---

## Module E — Pilot Company ↔ Pilot Driver Relationships

### Task E1 — Relationship model
Data object (§55) `pilot_company_driver_relationship`: `pilot_company_id, pilot_driver_id, requested_by, status, created_at, approved_at, revoked_at`.
Statuses (§29): Pending, Approved, Rejected, Revoked, Suspended.
Rules: many-to-many (a driver may be linked to multiple companies; a company to many drivers). Never automatic; both parties must approve.
Log for every action: who requested, who approved, when approved, who revoked, why revoked (if provided).

### Task E2 — Driver requests company
Driver initiates ("John says he works with ABC Pilot Cars and requests to connect"). Also created automatically as **pending** from the signup answer in Task A2. Company can: Approve, Deny, Request more information.

### Task E3 — Company requests driver
Company sends request ("ABC Pilot Cars wants to add you as a pilot driver"). Driver can: Approve, Deny, Ignore, Ask for more information. Once approved the company can assign the driver to assignments (Task H2).

### Task E4 — Relationship request email
Template "Pilot Company Relationship Request", subject `Pilot driver relationship request`, body explains a pilot driver or pilot company is requesting to connect profiles (Task J1).

---

## Module F — Pilot Access Scopes (Trip Sharing)

### Task F1 — "Manage Pilot Access" panel in trip workspace
Article §22, §56. New page/panel inside the trip workspace (`src/app/trips/[id]/trip-workspace.tsx`), available to carrier dispatcher, carrier company admin, broker (if allowed — Open Question 5), and internal admin.
Actions: invite pilot company, invite pilot driver, share one state, share multiple states, share one permit, share multiple permits, grant full trip access, remove access, change access, preview what the pilot can see (Task F6), resend invite, revoke invite, see pilot document status, see pilot verification status (readiness), see assigned pilot driver, see assigned pilot vehicle, view activity log.
Flow on the screen: invite pilot company/driver → select access scope (state / permit / full trip) → preview → send invite.
Rationale from article: pilots are often added after the trip is already created.

### Task F2 — Access scope data model (backend)
Scope types: `state`, `permit`, `full_trip`. **Do not build route-segment sharing** (explicit MVP decision).
Table `pilot_access_scope` (§51): `access_scope_id, trip_id, participant_id, scope_type, state, permit_id, can_view_permit, can_view_route, can_view_trip_overview, can_view_carrier_driver, can_view_carrier_company, can_view_carrier_unit, can_view_commodity, can_view_dimensions, can_view_rate_confirmation (always false for pilots), can_view_pilot_documents (role-dependent), can_ask_ai, can_order_route, can_message_assignment_chat, created_by, created_at, revoked_at`.
Multiple-state / multiple-permit sharing = multiple scope rows for the same participant.

### Task F3 — State access (dynamic)
If a pilot has state access for e.g. Ohio, the backend returns: all existing Ohio permits on the trip, **any Ohio permit uploaded later automatically**, routes for those permits, escort/curfew details, and operational trip info needed for those permits. No manual re-share per new permit. Use `permits.state_code`.

### Task F4 — Permit access (static)
Access tied to a specific `permit_id` returns only that permit, its route, its escort/curfew info, and relevant operational trip details. A later permit from the same state is **not** visible unless the pilot also has state access.

### Task F5 — Full trip access (operational, not commercial)
Pilot can see: all permits, all states, all routes, trip overview, carrier company info, carrier dispatcher contact, carrier driver contact, truck/unit info, trailer info, commodity, overall dimensions, weight, escort info, curfew info, pilot assignment chat, shared operational notes.
Pilot still cannot see: rate confirmation, broker/carrier pricing, broker margin, billing settings, W-9, driver license, business license, other pilots' certification files, private internal notes, company admin settings, unrelated documents, unrelated trips.

### Task F6 — Access preview
Before sharing, show what the pilot will see: visible states, visible permits, visible routes, visible driver info, visible carrier info, visible truck/trailer/commodity/dimensions, visible vehicle photos, hidden documents, "Rate confirmation hidden", "Unshared states hidden", "Pilot paperwork hidden from broker".

### Task F7 — Enforce scopes across every read path
The trip page (`src/app/trips/[id]/page.tsx`) currently signs URLs for every document and loads all permits/participants/events for any participant. For pilot participants, every server read must filter by their scopes: permits, documents, warnings, service requests/routes, participants list (no "full contact lists of unrelated participants"), events, chat, AI. Also: pilots cannot see unshared permits, unshared states, unshared documents, other trips, other pilot companies.

### Task F8 — Carrier and broker sharing permissions
- Carrier dispatcher: invite pilot company/driver, share states, share permits, grant full trip, revoke, preview.
- Carrier company admin: can override pilot access.
- Carrier driver: may share pilot access **only if carrier settings allow it** (Open Question 5).
- Broker: may invite pilots and share state(s), permit(s), or full trip operational access (if allowed). Broker can never share the rate confirmation and can never share pilot paperwork (broker cannot see it). System **may** notify the carrier when a broker adds a pilot, depending on trip settings (Open Question 5).
- Existing `INVITE_RULES` in `src/lib/domain/permissions.ts` already lets broker/dispatcher/driver invite `pilot`; adjust the driver case per the carrier setting.

### Task F9 — Rate confirmation hard block
Pilot users must never see the rate confirmation in any access type, including full trip, assignment history, AI chat, document list, mobile dashboard, and email links. `can_view_rate_confirmation` is always false for pilot roles. **Enforce in backend** (document listing, signed-URL generation, AI context, email variables such as `rate_confirmation_link`), not only hidden in the UI.

### Task F10 — Access update email
Template "Pilot Access Updated", subject `Your pilot assignment access was updated`, explaining that state or permit access was added or removed (Task J1).

---

## Module G — Pilot Assignment and Views per Role

### Task G1 — Pilot assignment record
Data object (§55) `pilot_assignment`: `trip_id, pilot_company_id, pilot_driver_id, pilot_vehicle_id, assignment_status, assigned_states, assigned_permits, created_by, created_at, completed_at`.
Statuses shown to broker (§46): invited, accepted, in progress, completed. Pilot role on assignment: lead, chase, high pole, etc. Pilot accepts the assignment as part of onboarding (Task A4). Completion email: "Pilot Assignment Completed", subject `Pilot assignment marked completed`, explaining status was updated and remains in history (Task J1).

### Task G2 — Broker view of pilot assignment
Simple pilot section in the trip. Broker can see: pilot company name, pilot driver name, phone, email, assigned states or permits, assignment status, pilot vehicle photos, vehicle basic profile, pilot role (lead/chase/high pole), whether a pilot was assigned, whether completed (if shared).
Broker cannot see: insurance, W-9, driver license, business license, certification files, certificate of good standing, any uploaded pilot paperwork or attached files, private pilot company records, carrier-private notes, pilot invoices.
Log "Broker viewed pilot assignment" (Task I1).

### Task G3 — Carrier view of pilot assignment
More detailed: pilot company, pilot driver, vehicle photos, driver phone/email, company phone/email, assigned states, assigned permits, assignment status, pilot documents, insurance status, W-9 status, license status, certification status, business license status (company), readiness status, activity log.

### Task G4 — Internal admin view
Broadest: pilot profile, pilot company profile, documents, vehicles, assignments, relationships, access scopes, audit logs, verification status, document status, invite history, support issues. All admin actions logged.

---

## Module H — Pilot Dashboards and Own Trips

### Task H1 — Pilot Company dashboard
Reuse the carrier dispatch dashboard structure (`src/app/dashboard/carrier-dashboard.tsx`) with pilot labels. Article's recommended tabs: All Assignments, Active Assignments, Pending Assignments, Completed / History, Pilot Drivers, Vehicles / Units, Documents, Contacts, Company Profile, Settings, Billing / Plan.
Note: the article's assumed carrier tabs ("Trips, Drivers, Fleet, Contacts, History") differ from the actual ones (All/Active/Pending/Completed Trips, Needs Review, Drivers, Reports). Mirror the real structure and map: Trips → Assignments, Drivers → Pilot Drivers, plus the added Vehicles / Units, Documents, Company Profile tabs. Billing / Plan: reuse existing `/billing` (Open Question 6).

### Task H2 — Pilot company assigns drivers to an assignment
When a pilot company is invited to a trip it can: view shared assignment, assign an approved pilot driver, invite a new pilot driver, link driver to assignment, link driver to vehicle/unit, replace assigned driver, remove assigned driver, notify carrier of assigned driver, update assignment status.
Carrier setting "Require carrier approval when pilot company assigns a driver: Yes/No" controls whether the carrier must approve the assigned driver (Open Question 5 for where this setting lives).
Log "Pilot company assigned driver".

### Task H3 — Pilot Driver dashboard
Reuse the carrier driver dashboard structure (`src/app/dashboard/driver-view.tsx`, swipeable mobile panes). Article's sections: Current Assignment, Shared Permits, Routes, Ask Agent, Messages, Documents, My Vehicle, My Profile, History. Simple and mobile-friendly. Content in every pane is limited to the pilot's scopes (Task F7).

### Task H4 — Pilot company and pilot driver can create their own trips
Both may create **private** trips without inviting a carrier, broker, or driver, to: store permit copies, ask AI, order routes, create a pilot assignment record, share with a pilot driver, prepare for a job, track history, organize documents. The creator controls that workspace. Reuse the existing trip creation flow (`src/app/trips/new`).

### Task H5 — Sharing pilot-created trips
Options: invite by email, share secure link, invite a pilot driver, invite a carrier dispatcher, invite a carrier driver, share trip info by link, keep private. Permissions and document privacy still apply.

### Task H6 — Route ordering for pilots
Pilots can order Express / Extended routes, view purchased route, ask AI about it, save route to assignment, share route with their assigned pilot driver if they control access.
- On a carrier-created trip: follow the trip's existing permission/payment rules (`service_requests.payer`, credits).
- On a pilot-created trip: order under the pilot's own account/plan.
Existing `canRequestServices` already returns true for the pilot trip role; make sure route deliverables are filtered to shared permits (Task F7). Log "Pilot ordered route".

### Task H7 — AI scoped by pilot access
`POST /api/trips/[id]/chat` currently sends all permits + full trip fields to the AI. For pilot participants, build the context only from: shared permits (state or permit scope), their routes, curfew/escort info, trip-level data allowed to the pilot, carrier/driver info shared with the pilot. With full trip access the AI can cover the full operational trip but must never reveal rate confirmation, pricing, billing, unshared private documents, pilot paperwork hidden from broker, or carrier/broker private notes. If a pilot asks about a hidden document, the AI must reply that the document is not available for their role. Log "Pilot asked AI question".

### Task H8 — Pilot Assignment Chat (scoped)
A separate chat scoped to the pilot assignment. Members: carrier dispatcher, carrier driver, pilot company, pilot driver. It must **not** automatically include the full broker/carrier trip chat. The existing single `chat_messages` room per trip needs a room/assignment discriminator or a new table (Open Question 7).

---

## Module I — Activity Log

### Task I1 — Pilot activity events
Extend `trip_events` (or add a pilot log) with these actions: pilot company invited, pilot driver invited, invite accepted, email validated, documents uploaded, documents approved/rejected, state access granted, permit access granted, full trip access granted, access removed, pilot company assigned driver, pilot driver assigned vehicle, vehicle added, vehicle photos uploaded, pilot asked AI question, pilot ordered route, pilot assignment completed, pilot access revoked, broker viewed pilot assignment, carrier viewed pilot documents.
Surface them in the trip History tab and in the Manage Pilot Access panel's activity log. Relationship actions are logged per Task E1.

---

## Module J — Email Templates

### Task J1 — Five pilot email templates
Add to `src/lib/email-templates.ts` (and the `/admin/email-templates` editor), with exact subjects:
1. **Pilot Assignment Invite** — subject `You were invited to a pilot assignment in HeavyHaul Agent`. Includes: carrier or broker name, trip reference, shared states or permits, role invited as (Pilot Driver / Pilot Company), required onboarding steps, secure workspace link.
2. **Pilot Document Required** — subject `Upload required pilot documents to view your assignment`. Explains that before viewing shared permits the pilot must validate email and upload required documents.
3. **Pilot Access Updated** — subject `Your pilot assignment access was updated`. Explains new state or permit access was added or removed.
4. **Pilot Company Relationship Request** — subject `Pilot driver relationship request`. Explains a pilot driver or company requests to connect profiles.
5. **Pilot Assignment Completed** — subject `Pilot assignment marked completed`. Explains status was updated and remains in history.
Email links must never expose the rate confirmation to pilots (Task F9).

### Task J2 — Actual email delivery
No email provider exists in the project today; invite links are copied manually. The article requires sending assignments, permit access, route access, document requests, AI notifications, and access updates by email, plus the validation email. Provider choice is Open Question 2.

---

## Not in scope (article §63, explicitly future)
State-specific certification rules, automated expiration alerts, public business-record verification, good-standing verification, pilot marketplace, availability calendar, dispatch board, pricing/quotes, performance history, ratings, check-in/out, GPS, **route segment sharing**, high-pole equipment verification, insurance expiration notifications, admin verification badge, document review workflow, compliance reminders, pilot route history, company reporting, pilot invoice workflow.

---

## Open questions

**Phase 1 (answered 2026-09-12):** scope = signup/onboarding + Pilot Dispatch dashboard + Pilot Driver interface, living with the existing design and preview tooling. Still open for Phase 1: should the carrier-side "Manage Pilot Access" panel and the broker/carrier pilot-assignment views also be mocked now?

**Needed before Phase 2 (can wait):**

1. ~~Self-signup~~ — **Answered**: yes, self-signup; Phase 1 is an admin-only front-end replica (Task P1).
2. ~~Email provider~~ — **Deferred** by client; no real email in Phase 1. Provider still to be chosen later.
3. **Pilot company storage.** Extend the existing `companies` table (`company_type` currently `broker|carrier`) with a `pilot` type, or create a separate pilot company table as the article's data objects suggest?
4. **Document approval.** Statuses include Pending Review / Approved / Rejected with `reviewed_by`, but "document review workflow" and "admin verification badge" are listed as future. For MVP, should admin have an approve/reject action on pilot documents, or are documents just Uploaded / Expired / Expiring Soon with review deferred?
5. **Where do the carrier settings live?** The article references: "carrier driver may share pilot access only if carrier settings allow it", "broker if allowed", "require carrier approval when pilot company assigns a driver: Yes/No", and "notify carrier when a broker adds a pilot, depending on trip settings". Should these be company-level settings (carrier company console), per-trip settings, or both? What are the defaults?
6. **Billing / Plan tab** for pilot companies: reuse the existing `/billing` page as-is?
7. **Pilot Assignment Chat**: implement as a second room inside the existing `chat_messages` table (room discriminator), or a new table?
8. **Existing pilot participants.** Trips that already have a `pilot` trip-role participant (invited via the current flow) today see everything. After this work, should those existing rows be treated as full-trip scope minus rate confirmation, or require re-sharing?
