# DESIGNS · flagship round 1 · index · setup journey · create · edit · swatch rows · Bulk Hub · brand-006 RJ Laravel Admin

**Sheet:** https://designs.pina-brand-006-rj-laravel-admin.pages.dev/ · **artboards:** /canvas/ (3 pages: Index · journey · create / Edit · swatches / Bulk Hub · states · phone) · **one image:** /contact-sheet.png
**Status:** round 1 for Frank's review, 2026-10-18. Design only; no code, no ledger, no commits.
**Boards:** 28 = 1 summary + 27 (Index 4 · Journey 2 · Create 3 · Edit 5 · Swatch rows at scale 4 · Bulk Hub 4 · States 4 · Phone 1). Each board = burned-in label chip + the screen at 1440×900 in the locked 4b·R shell + an annotation panel (decisions, sources, tags).
**Source:** `src/d_catalogue.py` (catalogue snapshot) · `src/d_data.py` (vocabulary, every item cited) · `src/d_pages.py` (screens) · `src/d_build.py` (composites, shots, sheet, canvas, dist) · `src/designs.css`. Shell + helpers reused from the Orders flagship (`../orders/src/o_pages.py`, `orders.css`) and the archetype shell (`phase-2/archetypes/src`). Build: `python3 src/d_build.py [--no-shoot] [--only E01,H03] [--dist DIR]`.

## Truth rules applied on every board

- **Real catalogue only.** Every product, design id, the four names (System EN/CN, Printer EN/CN), type, surcharge cm, popup row count, swatch code, printer string and supplier comes from the local prod dump (laravel-rds `prod_dump`, 18 Oct), cross-checked with the read-only prod MCP (`get_product_structure`, `get_design_popup_config`, `get_design_rules`, `get_supplier_directory`). Catalogue data, not personal data.
- **Code at 3.0_Backend `origin/main` 6787e7873** (same commit as TRUTH-DESIGNS; `git fetch` + `git show` only, no working copy).
- **The flagship example** is Jacket (1) › Jacket Lining (940, No Design Output) › **Half (945)**: type 8, System `Half` / `半里-弯挂面-里布到叉-蝴蝶形后`, Printer `Half Lining` / same CN, 20 cm, component JA Lining (9), Show in Bulk Hub on, 171 popup rows (34 plain PT · 137 pattern; SQF 70 · SYC 71 · SHONG 28 · SJSY 2).
- **Nine real types** with their seeder labels + "No Design Output". No "option", no "Option group", no "radio/option" field type.
- **Surcharge is cm of fabric**, never money. **Supplier is a name** (SQF, SYC, SHONG…), derived from the binding on type 8/9 rows.
- **Blockers read "Blocked by"** with the real prompt; the example is the real rule #2 (650 Machine | Last blocked by 39 Hand).
- **Bulk Hub lists opted-in designs only** (the real 11 groups); Export is a direct JSON download; no job tray entry; no Import JSON on the design page.
- Images (garment + swatches) are **stand-ins**: every real row has an image on the CDN; they are not re-hosted. Dotted underline = example value. Tags: purple dashed = proposal, amber dashed = needs backend, blue = API only.

## Boards

| Key | Board | What it decides | Main sources |
|---|---|---|---|
| X01 ★ | Designs index · Jacket | product list left (15 products, counts) · tree table (categories shaded, options nested) · all four names as columns · Type · Surcharge (cm) / "N rows" · popup Rows · Links · Flags (Hub · Online · Frame) | `index.blade.php:39-120`, `DesignController::index :138-151`, Wave21 index (product required) |
| X02 | Filters · saved views | Surcharge (cm) only (= "Show Meter surcharge Items") · Type / Error validation / Bulk Hub chips · search in the 4 names (client-side) · views (H01) | `index.blade.php:6-16`, `BuyingSheet.php:44-50` |
| X03 | Sort Designs · Shirt | the real sort modal (Collar 128 mid-drag), options drag inline | `index.blade.php:141-173`, `admin.sorting` |
| X04 | Long strings + CJK | Shoulder / Panel Adjustment CN names wrap; Printer CN SH01–SH06 | prod designs 2…791 |
| J01 ★ | Setup journey · 21 steps | map by phase lane; every step with its page/screen, what it needs, which board draws it; gaps marked | TRUTH §2 |
| J02 | How you'd use it | 8 pinned steps on the Half swatch page | — |
| C01 ★ | Create · category or option · type | Parent "Open New Category" fork · type list (9 + No Design Output) · four names 2×2 · category settings | `create.blade.php:53-205` |
| C02 | Create an option (Half) | type inherited · template · two doors (Materials, Image) · **G1 surcharge drop drawn red** · type-8 black boxes | `DesignController.php:220-231, 249-257, 386-412` |
| C03 | Add from Materials | Cloth · Thread · Side Adjuster · Accent Fabric · Button · Plain/Pattern · Online/Offline/All · multi-select · warning badges | `_canonical-picker-modal.blade.php:36-98` |
| E01 ★ | Edit · Identity | section nav · read-only product/parent/type · **four names side by side + System-vs-Printer card with 4 real examples** · image | `edit.blade.php:9-35, 205-259` |
| E02 ★ | Edit · Swatches | all 12 inputs per row · real toolbar · filter chips by plain/pattern/supplier · 11 "OUT-OF-STOCK |" labels flagged | `edit.blade.php:389-665` |
| E03 | Edit · Production + Rules + Validation | info · no design-level supplier on type 8 · 20 cm · JA Lining · links · SP codes · blockers · validation · hub · retailer coverage ghost (G3) | `edit.blade.php:737-1052`, `DesignMetaController` |
| E04 | Edit · Rules · Blocked by | real rule 650 ← 39 Hand + real links 645/646/647 · same-product picker · active switch lives in the module | prod `design_blockers`, `design_links` |
| E05 | Edit a category (617) | camera frame menu (not set · No frame · Monogram frame 绣字取景框 · retired) · custom-text blocks · FT/HT options · "null" printer labels found | `edit.blade.php:290-372, 39-76` |
| S01 ★ | Inline edit at scale | the two save paths visible: bulk bar saves instantly (toast) vs row edits amber until Save (50 per chunk) · keyboard grid (proposal) | `edit.blade.php:1302-1308, 1819-1880` |
| S02 | Bulk paste into a column | paste N lines into one column of N selected rows · before→after · points to Bulk Hub Mappings | proposal (client-side fill) |
| S03 | Rebind a used swatch | fork-on-change: "Also update N past order(s)" unticked by default · the order-impact truth table | `_canonical-picker-modal.blade.php:76-90`, `_order-impact-table` |
| S04 | Delete selected · duplicates merged | the two real modals | `edit.blade.php:2353`, help "Duplicates & restores" |
| H01 ★ | Bulk Hub | the real table, 11 groups, leaf parents, 4 actions per row | `bulk-hub/index.blade.php:77-251` |
| H02 | Find / Replace | Remove "OUT-OF-STOCK | " across Jacket Lining (a clean-up the data needs) | `_popup-bulk-offcanvases.blade.php:36-104` |
| H03 | Preview · Apply · stale | the 6 buckets, before→after on real rows, atomic apply, 409 stale state | `index.blade.php:696-701`, `BulkDesignHubController.php:348-530` |
| H04 | Mappings · duplicate labels | Paste CSV match,value (real printer strings) · Append/Replace · dup popover | `_popup-bulk-offcanvases.blade.php:114-225` |
| T01 | Images + save jobs | Select File media library + per-file upload list (proposal) · "Saving linings… 3/4" chunks of 50 + meta · failed chunk + truncation guard | `create.blade.php:222-237`, `edit.blade.php:1654-1700`, `DesignController.php:195-216` |
| T02 | Validation summary | one summary with jump links; real rules only; **no version/conflict state** (not real) | Wave21 `UpdateDesignRequest` |
| T03 | Permission denied | read-only role: Save/Delete/Materials/Image/bulk bar absent; names copyable | `AdminPermissionsSeeder.php:71-84` |
| T04 | Long strings + CJK on edit | Spalla'05 (31-char CN) · the 78-char lapel labels | prod |
| M01 | Phone /m/designs | **read-mostly** (no phone evidence for long edits; STACK §2 / ARCHETYPES A03): product chips → categories → four names + facts → swatch grid; Copy names · Open on desktop | STACK-AND-PACKAGES §2 |

## Data findings (real, surfaced while grounding)

1. **11 of Half's 171 rows** still carry the legacy `OUT-OF-STOCK | ` prefix in all four labels (e.g. `OUT-OF-STOCK | YC15016`), although out of stock is now computed from the colour's codes. H02/H03 show the Bulk Hub clean-up.
2. **20 fields store Printer EN as the literal string "null"** (incl. 617's Text 4755 and Italics 4756).
3. **Placeholder CN names:** 789 "No Adjustment" System CN = `.`, 944 "Custom Lining" System CN = `...`.

## Open questions for Frank (labelled options)

1. **Where do swatch rows live on the edit page?** 1a · one section in the section nav, same page, one Save (drawn) · 1b · their own tab/page per design (the 171-row table loads separately).
2. **System vs Printer explanation card** — 2a · always visible in Identity (drawn) · 2b · collapsed behind an ⓘ after first use.
3. **Index "status" column** — designs have no status today. 3a · flags only: Hub · Online · Frame (drawn) · 3b · add "Retailers carrying / priced" (needs backend G3).
4. **Saved views on the designs index** — 4a · personal (H01) · 4b · not needed; the product list is enough (the index is one product at a time).
5. **Fix the surcharge-drop on create (G1)** — 5a · persist `extra_meter` on create (web + API store) · 5b · remove the field from create and set it on Edit only.
6. **Keyboard grid on swatch rows (S01)** — 6a · yes (UI only) · 6b · keep plain inputs.
7. **Bulk paste into a column (S02)** — 7a · yes, client-side fill for the selection · 7b · no; Bulk Hub Mappings only.
8. **"OUT-OF-STOCK |" prefixes** — 8a · clean them now with Bulk Hub Remove (H02, Jacket Lining + any other group) · 8b · leave; hide the prefix in the UI.
9. **Camera frame + supplier on create (G2)** — 9a · add to create (API store already accepts camera_frame) · 9b · keep after-save only.
10. **Blocker active switch on the design page (G4)** — 10a · show it (API `blockers.*.is_active`) · 10b · keep it in the Design Blockers module (drawn).
11. **Bulk Hub per-row actions** — 11a · keep the four buttons on every row (real today, drawn) · 11b · show them on hover / one ⋯ menu per row.
12. **Phone** — 12a · read-mostly lookup (drawn) · 12b · allow one edit on phone (e.g. surcharge cm), else desktop.

## Needs backend

| # | Gap | Evidence | Proposal |
|---|---|---|---|
| **G1** | **Create silently drops the surcharge** (design `extra_meter` and every popup row's `extra_meter`) | `create.blade.php:145-147, 436` post it; `DesignController::store` `$data` `:249-257` and popup `Field::create` `:386-412` omit it; only update persists (`:743-748, :960-962`) | persist on create (web + Wave21 store) or drop the input |
| G2 | Camera frame + supplier only after the first save | not on `create.blade.php`; API `StoreDesignRequest` accepts `camera_frame` | add to create |
| G3 | No read of which retailers carry / have priced a design | `user_main_product_design` has no by-design read | read endpoint → "Retailers carrying this option" panel (E03) |
| G4 | Blocker `is_active` not on the web edit form | API `UpdateDesignRequest` `blockers.*.is_active` | wire it if the toggle is wanted |
| G5 | Edit path has no `max:1000` on info | store/API have it | align |
| G6 | Per-design popup bulk routes registered but UI retired | `web.php:418-437` | retire or bring back deliberately |
| G7 | No version/ETag on design update → no "someone else changed this" | Wave21 `UpdateDesignRequest` has no version field | add `expected_version` like measurements (T02 ghost) |
| H01 | Saved views storage | prefs store holds locale + timezone only | per-person prefs (shared with Orders) |

## Could not verify

- Which design permissions the live **orders** role holds (T03 assumes view-only; the orders role menu does show Designs).
- The real **past-order count** for a swatch (S03 shows an example; `GET designs/{design}/popups/{field}/order-refs` returns it live).
- The alexusmai **file manager's own upload UI** in this skin (T01 draws the proposed per-file list).
- The real images (stand-ins drawn; paths are real, e.g. `new-order-compressed/components/lining/qf/pattern may 2025/BX-QF911935.webp`).
