# Nobel Auto — Platform Test Plan

Executed against a freshly migrated + seeded dev database (`prisma migrate reset` + seed).
Legend: ✅ pass · ❌ fail (issue logged) · 🔧 fixed and re-verified.

## A. Authentication & sessions
| # | Test | Expectation |
|---|------|-------------|
| A1 | Login with each seeded role (admin, staff, technician, accounts) | 200, `{user}` only (no token in body), httpOnly cookies set |
| A2 | Login with wrong password | 401 |
| A3 | Login with malformed body | 400 with field errors |
| A4 | `GET /auth/me` with cookie | 200 profile |
| A5 | `GET /auth/me` without cookie | 401 |
| A6 | `POST /auth/refresh` with cookie | 200, cookies rotated |
| A7 | `POST /auth/logout` then `/auth/me` | 401 after logout |
| A8 | Rate limit headers present on login | RateLimit-Limit: 20 |

## B. Customers (core flow step 1)
| # | Test | Expectation |
|---|------|-------------|
| B1 | Staff creates customer (name+phone only) | 201, portalToken auto-generated |
| B2 | Create with empty name | 400 |
| B3 | Get customer detail | 200 incl. vehicles + orders |
| B4 | Search customers by name/phone fragment | matching rows |
| B5 | Staff PATCH customer email/tier | 200 updated |
| B6 | Technician tries create | 403 |
| B7 | Admin soft-deletes; customer disappears from list | 200 then absent |
| B8 | Missing id PATCH | 404 (not 500) |

## C. Vehicles (core flow step 2)
| # | Test | Expectation |
|---|------|-------------|
| C1 | Staff adds vehicle to customer | 201 |
| C2 | Duplicate VIN | 409 |
| C3 | Vehicle create with year 1800 | 400 |
| C4 | Search vehicles by plate | match |
| C5 | PATCH miles | 200 |
| C6 | Admin delete (soft) | 200 |

## D. Work orders + line items (core flow step 3)
| # | Test | Expectation |
|---|------|-------------|
| D1 | Staff creates order for customer+vehicle | 201, WO-# sequential, taxRate snapshot |
| D2 | Vehicle not owned by customer | 400 |
| D3 | assignedTo non-technician | 400 |
| D4 | Add part (linked to inventory), labor, custom items | 201 each |
| D5 | Edit line item qty/price | 200 |
| D6 | Delete a line item; item from another order id | 200 / 404 |
| D7 | Technician sees only own orders; foreign order detail | 403 |
| D8 | Accounts role edits order | 403 |
| D9 | Invalid status jump (draft→paid) | 400 |
| D10 | Valid transitions draft→in_progress→ready | 200 |

## E. Billing / finalize / receipts (core flow step 4 — must be frictionless)
| # | Test | Expectation |
|---|------|-------------|
| E1 | Finalize order **without any customer approval** | receipt created — approval must never gate billing |
| E2 | Finalize directly from draft/in_progress (walk-in) | must work (friction check) |
| E3 | Receipt has money snapshot (subtotal/discount/tax/total) | matches calcOrderTotals |
| E4 | Inventory stock decremented by part qty | stock reduced |
| E5 | Finalize with insufficient stock | 409, transaction rolled back |
| E6 | Finalize empty order | 400 |
| E7 | Finalize already-paid order | 400 |
| E8 | Edit paid order / its items | 400 |
| E9 | Refund receipt; refund again | 200 then 409 |
| E10 | **Print bill** from receipt | printable invoice with shop info, items, totals |

## F. Inventory
| # | Test | Expectation |
|---|------|-------------|
| F1 | List with global stats (not per-page) | stats over full table |
| F2 | filter=low / filter=out | correct subsets |
| F3 | Admin create/patch/delete item; staff blocked | 201/200/200; 403 |
| F4 | Duplicate SKU | 409 |

## G. Reports (admin/accounts)
| # | Test | Expectation |
|---|------|-------------|
| G1 | Revenue with valid range | totals incl. snapshot receipts |
| G2 | `from=garbage` | 400 |
| G3 | Staff blocked | 403 |
| G4 | orders/customers/inventory reports | 200 |

## H. Users & settings (admin)
| # | Test | Expectation |
|---|------|-------------|
| H1 | Admin lists/creates/updates user; staff blocked | 200/201/200; 403 |
| H2 | Duplicate email user | 409 |
| H3 | GET/PATCH shop settings; staff blocked | 200; 403 |

## I. Public site API (guest-facing)
| # | Test | Expectation |
|---|------|-------------|
| I1 | GET /public/shop, /public/services | real Scarborough info; 8 active services |
| I2 | Availability skips Sundays, past days, full slots | correct grid |
| I3 | Guest booking with minimal fields | 201, APT-# |
| I4 | Booking with portal token + own vehicle | linked customerId/vehicleId |
| I5 | Token booking with someone else's vehicleId | 400 |
| I6 | Slot capacity exhausted | 409 |
| I7 | Invalid slot / past date / unknown service / closed day | 400 each |
| I8 | Booking rate limited | headers present |

## J. Admin appointments
| # | Test | Expectation |
|---|------|-------------|
| J1 | List with status filter + search | matches |
| J2 | Confirm pending → confirmed | 200; invalid transitions 400 |
| J3 | Reschedule to open slot | 200 date/slot updated |
| J4 | Cancel with reason | 200 cancelReason stored |
| J5 | Convert guest appt → creates customer+vehicle+order with service line item | 201 |
| J6 | Convert linked appt → uses existing customer/vehicle | 201, no dupes |
| J7 | Convert cancelled appt | 400 |
| J8 | Technician/accounts blocked from appointments | 403 |

## K. Portal (track-my-repair)
| # | Test | Expectation |
|---|------|-------------|
| K1 | GET portal data by token | customer + currentOrder + history + appointments |
| K2 | Bogus token | 404 JSON (server stays alive) |
| K3 | Approve without staff request | 409 (approval is opt-in) |
| K4 | Staff requests approval → portal approve → status approved | 200 chain |
| K5 | Decline with reason stored | 200 |

## L. UI wiring audit (code-level + compile)
| # | Test | Expectation |
|---|------|-------------|
| L1 | Every ops page's query params match API (search vs q) | consistent |
| L2 | Every ops mutation payload matches zod schema | consistent |
| L3 | All routes compile under Vite; no stale .js shadowing | clean |
| L4 | New-order flow reachable from customer detail (frictionless path) | ≤ 3 clicks customer→order |
| L5 | Web booking wizard param/payload match | consistent |
| L6 | Landing page assets/images load | 200s |

## Results — see PR/commit description and `docs/TEST-RESULTS.md`.
