# Orders-Note — Technical Design

> Produced by the Reversa **Writer** (phase: generation) · doc_level: `complete`
> Generated on 2026-09-21

**Confidence scale:** 🟢 CONFIRMED · 🟡 INFERRED · 🔴 GAP

## Interface

Single HTML `PUT` endpoint, admin group (`['web','admin']`, empty admin prefix), route name `orders.update_note`. 🟢 (`routes/web.php:74`)

| Method | Path | Input | Output | Status codes |
|--------|------|-------|--------|--------------|
| PUT | `/orders/{order}/note` | path `order` id; body `notes?: string` (form field, `nullable|string`) | `302` redirect back (with a flashed toastr / errors) | 302 (redirect back on success or failure; → `auth/login` when unauthenticated), 404 on unknown id, 422/redirect-back on validation failure |

Controller symbol:

| Symbol | Signature | Return | Note |
|--------|-----------|--------|------|
| `OrderController::updateNote` | `(Request $request, $id)` | `RedirectResponse` | Validates `notes` (`nullable|string`), `Order::findOrFail($id)`, `fill($valided)`, `save()`; success → toastr + `redirect()->back()`; failure → `back()->withInput()->withErrors('Cập nhật thất bại')`. 🟢 (`:342-356`) |

## Main Flow 🟢 (`:342-356`)

1. `PUT /orders/{order}/note` reaches `updateNote($request, $id)` via the admin group (route registered before `resource('/orders')`, and on a distinct path, so it is not shadowed). 🟢 (`routes/web.php:74`)
2. `$valided = $this->validate($request, ['notes' => 'nullable|string'])`. 🟢 (`:344-346`)
3. `$product = Order::findOrFail($id)` — 404 on miss. (The local variable is named `$product`, a copy-paste artifact; it holds an `Order`.) 🟢 (`:348`)
4. `$product->fill($valided)` — assigns only `notes` (bounded by `Order::$fillable`). 🟢 (`:349`)
5. `if ($product->save())` → `admin_toastr(__('Cập nhật thành công'))` and `return redirect()->back()`. 🟢 (`:351-353`)
6. Otherwise → `return back()->withInput()->withErrors('Cập nhật thất bại')`. 🟢 (`:355`)

## Alternative Flows

- **Empty note:** `notes` absent/empty passes `nullable` and clears the annotation. 🟢 (`:345`)
- **Non-string note:** fails `string` validation → Laravel redirects back with the validation error bag (no save). 🟢 (`:345`)
- **Unknown id:** `findOrFail` raises `ModelNotFoundException` → clean `404`. 🟢 (`:348`)
- **Save returns false:** redirect back with old input + `Cập nhật thất bại`. In practice `save()` returns `false` only when a `saving` model event halts it; `Order` defines none, so this branch is effectively unreachable. 🟡 (`:355`; `Order.php`)
- **Unauthenticated:** admin group middleware → `302 auth/login`. 🟢 (`routes/web.php:24-28`)

## How the note form is rendered

Both reader screens emit a Laravel `Form::open(['route' => ['orders.update_note', '#id#'], 'method' => 'PUT'])`, where `#id#` is a placeholder string that the page's JavaScript replaces with the concrete order id when the per-order note modal/inline editor is opened. `Form::open` emits the CSRF token and the `_method=PUT` spoof field required to reach this route through the `web` middleware. 🟢 (`customer-statis.blade.php:183`, `customer-orders.blade.php:121`)

## Dependencies

- **`Order` model** — the subject; `findOrFail` loads it and `$fillable` bounds the write to `notes`. 🟢 (`app/Models/Order.php:11`)
- **`admin_toastr` / `withErrors`** — user feedback via the admin flash channels. 🟢 (`:352,355`)
- **`customers-statistics`** — renders the note editor and consumes `notes` as its "annotated orders" filter (`whereNotNull('notes')`). 🟢
- **`customers-purchase-history`** — the other screen that renders the note editor. 🟢

## Identified Design Decisions

| Decision | Evidence in code | Confidence |
|----------|------------------|------------|
| A dedicated single-column endpoint instead of routing note edits through the full `orders-crud` `update` (which recomputes totals/points/debt) | separate route + `updateNote` touching only `notes` | 🟢 (`:342-356`) |
| Redirect-back (PRG) contract, not JSON — driven from server-rendered forms | `redirect()->back()` / `back()->withInput()` | 🟢 (`:353,355`) |
| No status/editability guard on note edits (notes are metadata, not financial state) | absence of `is_editable`/status check | 🟢 (`:342-356`) — confirmed intentional 2026-09-25 |
| Mass-assignment safety via `Order::$fillable` rather than an explicit `$order->notes = …` | `fill($valided)` | 🟢 (`:349`; `Order.php:11`) |

## Internal State

None held in the controller. The action mutates exactly one persisted column (`orders.notes`) and performs no other write. 🟢 (`:342-356`)

## Observability

None. The action emits no log, metric, or trace; a failed save (the `Cập nhật thất bại` path) produces only a user-facing flash, no structured signal. 🔴 (`OrderController.php:342-356`, absence)

## Risks and Gaps

- 🟢 **Confirmed intentional (2026-09-25): no status/editability guard.** Unlike `orders-crud` `update`, `updateNote` has no `is_editable`/24h/status check — any order's note is editable indefinitely. Notes are free metadata, not financial state. `questions.md#question-14` closed.
- 🟡 **`$product` variable name.** The loaded `Order` is stored in a variable named `$product` — a harmless copy-paste artifact, but a readability trap on reimplementation. (`:348`)
- 🟡 **Unreachable failure branch.** `save()` returning `false` requires a halting `saving` event, which `Order` does not define; the `Cập nhật thất bại` path is effectively dead. Keep it for parity or drop it on reimplementation. (`:351-355`)
- 🟡 **No per-record authorization.** Any authenticated admin can edit any order's note. (ADR-0009)
- 🔴 **No observability** on the write path (see above).
