# PRD — LWR (Lab Work Request) Module

## 1. Document Metadata

| Field | Value |
|---|---|
| **Title** | PRD — LWR (Lab Work Request) Module |
| **Module** | LWR (customer lab-work request workflow — exact legacy scope to be confirmed) |
| **Status** | **Phase 0 — frontend scaffold only (2026-06-11).** Four page files copied into `Pages/MenuLWRs/`; **nothing is wired** (no routes, controller, policy, sidebar, models, tests, build). The module is not reachable in the app. Follow-up tracked in **issue #46**. |
| **Owner** | IT — PT Colorindo Chemtra |
| **Date** | 2026-06-11 |
| **Stack** | Laravel 13.8 / Inertia.js v3 / React 19.2 / Tailwind v4 / MySQL 8.4 |
| **Document Type** | Honest scaffold PRD — documents exactly what the copied files are today; everything beyond that is explicitly marked TBD/unverified. Mirrors the structure of `MenuSampleOrders/SampleOrder PRD.md`. |

---

## 2. Overview & Purpose

The **LWR** module will manage customer **Lab Work Requests** — requests for laboratory work on products (microbiology, formulation, analytical labs, per the prototype's field inventory). It is the third transactional module being ported from the legacy app, after Quotations and Sample Orders.

**Construction lineage (deliberate, decided 2026-06-11):**

- **List / Detail / Approval PM** are **verbatim copies** of the `MenuSampleOrders` pages (which were themselves adapted from the Quotation template). **Sample Orders is reference-only for this module** — the copies are structural starting points, not the spec.
- **Create** is a copy of the NewUI prototype `Pages/Proto/LWR/Create.jsx` (the proto original is untouched and still renders under Proto).
- New top-level page group **`MenuLWRs/`** (name confirmed by user 2026-06-11 — "match the SampleOrders pattern", per the CLAUDE.md `Pages/<Group>/<Module>/` grouping rule).

---

## 3. Scope

### 3.1 Shipped this pass (Phase 0 — 2026-06-11)

Exactly four page files plus this PRD. Constraint honored: **nothing outside `resources/js/Pages/` was touched.**

| File | Copied from | State |
|---|---|---|
| `LWRs/List.jsx` | `MenuSampleOrders/SampleOrders/List.jsx` | Verbatim — still reads "Sample Order" throughout |
| `LWRs/Detail.jsx` | `MenuSampleOrders/SampleOrders/Detail.jsx` | Verbatim |
| `LWRs/Create.jsx` | `Proto/LWR/Create.jsx` | Prototype — mock data, no form transport |
| `ApprovalPm/Index.jsx` | `MenuSampleOrders/ApprovalPm/Index.jsx` | Verbatim |

All four use only `@/` alias imports (verified), so they remain valid at the new path.

### 3.2 Explicitly NOT shipped

- **No rename/adaptation:** the three sample-order copies still call `route('sample-orders.*')`, persist column state under `sampleOrderColumnsState_v1`, and carry sample-order columns/statuses/tone maps.
- **No backend or wiring:** no routes, controller, policy, FormRequest, models, sidebar rows, or tests.
- **No build:** nothing references the new files, so the served prebuilt bundle is unaffected; `npm run build` is only needed once pages are wired.
- **No legacy verification:** the Create page has not been checked against the legacy LWR create rules.

---

## 4. Users & Permissions — TBD

Nothing exists. Expected to mirror the Sample Order pattern when built: rolemenu-driven sidebar visibility + a policy funneling through `User::canAccessMenuLink()` — to be decided at the wiring/read pass.

---

## 5. Data Model — UNVERIFIED

- **No `DESCRIBE` has been run.** Per CLAUDE.md this is mandatory before any model/backend work.
- Known hints only (do not treat as facts): the legacy app has an LWR module (`listlinkwithlwr.php` exists in the Sample Order legacy reference folder), and the Sample Orders module already reads LWR rows for its Link-with-Other tab (`sample-orders.related` type `lwr` → `SampleOrderController::related()`) — that code is the first place to learn the real table shape. Expect the project's `<entity>` + `<entity>assignment` + `<entity>status` family pattern, but **verify, don't assume**.

---

## 6. Functional Requirements — current honest state

### 6.1 List / Detail / Approval PM (verbatim sample-order copies)

These behave exactly as documented in `SampleOrder PRD.md` §6.2–6.4 (same code). Every column, status map, route call, and label says "sample order" until the adaptation pass. **Do not wire routes to them as-is.**

### 6.2 Create (prototype) — field inventory as copied

- **Header:** breadcrumb "Lab Work Request › Create LWR"; badges **"Transaksi OK"** + **"Pending LWR: 12"** (mock — implies a legacy submission-limit gate analogous to the Sample Order `SampleOrderLimit` BR-13; **verify**); Reset / Create LWR buttons (no handlers).
- **Step 1 — Document Header:** Company (`SearchableSelect`, mock companies), Division (select — mock hardcodes *Coating* / *Laboratorium Care*; verify whether lab-division restriction is a real rule), Industry (readonly), company Address display; Company CP + CP info; Project Title*; Project Initiator* (hardcoded names — mock).
- **Step 2 — Project Details:** Expectation of Customer*, Expectation of Project Initiator*; Lab Requirements (Microbiology, Formulation Lab, Analytical Lab, Other Lab — optional); Method Details (Specific Method*, Special Instructions*, Proses Method*, Remark); Attachment "Work Metadata" upload (pdf/doc/docx/xls/xlsx/ppt/pptx, "Max 2MB" note — input not wired).
- **Step 3 — Product Details:** add via `LwrProductModal` (shared `Components/Proto/Modals/LwrProductModal.jsx` — outside Pages, untouched); 15-column table: Product From, Competitor, Principal, Product Name, Colour, Type/Form, Volume Test, Satuan Vol, Price (USD), Satuan Price, Potential Vol, Potential Values, Remark, Edit, Delete. Inherited NB warning about edit requiring product re-selection; Edit has no handler (Delete works client-side).
- **Link with Other (Optional):** tabs Quotation / Sample Order / VisitReport with mock rows.
- **Tech state:** client `useState` only; mock `data` from `@/Proto/data`; **no `useForm`/`useHttp`**; component `LwrCreate`, `layout = [AppLayout]` (array form). Required markers (*) are visual only.

---

## 7. Validation Rules — none exist

Legacy rules must be extracted before the create/store pass.

---

## 8. Routes / API — none exist

Candidate names (NOT locked): `lwrs.*` following `sample-orders.*`, or a longer kebab form (`lab-work-requests.*`) — decide at wiring time per CLAUDE.md route conventions (kebab-case lowercase plural).

---

## 9. UI / UX Requirements

- Pages resolve by path (Inertia v3): controllers must render `'MenuLWRs/LWRs/List'`, `'MenuLWRs/LWRs/Detail'`, `'MenuLWRs/LWRs/Create'`, `'MenuLWRs/ApprovalPm/Index'`; tests must assert the same component strings.
- Every page keeps `Component.layout = [AppLayout]` (array form).
- Create is **prototype-styled** (FloatingField / SearchableSelect / Pill / TabBar, gradient pill buttons) — re-theme to utility/shadcn is a later follow-up, same posture as Sample Order Create (`SampleOrder PRD.md` §9.4).
- **Build constraint:** the app serves a prebuilt Vite bundle — `npm run build` required once the pages are wired.

---

## 10. Business Rules & Constraints — TBD

Candidates to verify against legacy before implementation (none are established):

- LWR submission-limit gate (the "Pending LWR" badge).
- Division restricted to lab divisions? (proto hardcodes Coating / Laboratorium Care — rule or mock?)
- Link-with-Other persistence rules (Quotation / Sample Order / Visit Report).
- **Sales display:** project default is the creation-time `UserIDSales` snapshot, but per standing user instruction — **ASK the user before applying the snapshot pattern to this new module.**

---

## 11. Non-Functional Requirements

Inherits the project stack and security posture (auth middleware, policy-gated actions, soft-delete `IsDeleted` pattern). Nothing module-specific yet.

---

## 12. Acceptance Criteria / Test Coverage

None — no behavior shipped. Verification of this pass = the four files exist at the §3.1 paths as byte-identical copies of their sources (checked with `diff -q`, 2026-06-11), and `git status` shows only new untracked files under `Pages/MenuLWRs/`.

---

## 13. Edge Cases & Known Constraints (of the current scaffold)

- The three sample-order copies would silently call sample-orders endpoints if rendered — **never route to them before the adaptation pass**.
- **localStorage collision:** `List.jsx` still uses `sampleOrderColumnsState_v1` — rename during adaptation or LWR and Sample Order lists will share column state.
- `Create.jsx` depends on assets **outside Pages**: `Components/Proto/Modals/LwrProductModal.jsx`, `Components/Proto/UI/*`, and `@/Proto/data` — removing the Proto tree would break it until the real-data pass.
- The status-tone map duplication noted in `SampleOrder PRD.md` §9.5 now exists in three more files; the extraction follow-up grows accordingly.

---

## 14. Roadmap / Future Enhancements

In intended order; nothing below is design-locked. All tracked in **issue #46**; each pass follows the playbook phase-4 per-feature workflow.

1. **Adaptation pass:** rename the three copies to LWR (titles, identifiers, localStorage key) and replace sample-order columns/statuses with LWR equivalents — verify against legacy LWR screens first.
2. **Wiring pass:** routes + sidebar menu/rolemenu rows (equivalent of Sample Order Phase 1).
3. **Read pass:** `DESCRIBE` legacy `lwr*` tables → models → controller + policy + Pest tests (equivalent of Sample Order Phase 2).
4. **Create/store pass:** extract legacy create rules → FormRequest + transactional store + Create on `useForm`/`useHttp` (equivalent of Sample Order Phase 3).
5. **Approvals / downstream workflow** and the utility/shadcn re-theme of Create.
