# Dashboard flagship · round 2 · 2026-10-19

## Decision (2026-10-19)

Frank: *"I green light the dashboard, I accept it."* Round 2 is accepted: the default dashboard (D1–D5) stands as drawn.

On the 18 power-ups in section 4, he said to *"skip for now, save to our global RJ admin file for future reference by me if I need"*. None is adopted now. They are parked in `phase-1/kit/PATTERNS.md` ("Dashboard power-ups (parked 2026-10-19)") with the ★ flags kept as "recommended if revisited". The new helpers H29 to H32 are tagged *backlog (parked with dashboard power-ups)* in `PROPOSALS.md` (PR-083 to PR-086). H01 and H06 are still needed by other adopted items.

Frank accepted Gantt round 2 on 2026-10-19 ("amazing, perfect, I accept all of this"). On the dashboard he asked: *"What upgrades can I get? My own screens, decide how screens are ordered, drag and drop containers, choose things collapsed by default, only render things that are meaningful… The system is becoming agentic, humans go here less, but still, maybe there's some really cool advanced stuff."*

- Boards: https://dashboard.pina-brand-006-rj-laravel-admin.pages.dev/ · artboards `/canvas/` · live power-ups `/powerups/` (phone `/powerups/m/`) · the gantt r2 boards D1–D3 are kept at `/from-gantt-r2/`
- Source: `src/` (`d2data.py` data, `d2.py` widgets and pages, `d2.css`, `d2boards.py` boards and sheet, `d2_build.py` build). It reuses the gantt r2 and r1 renderers read-only (`../gantt/r2/src`, `../gantt/src`). Power-ups: `powerups/src/dpu-data.js` (cards and backend specs), `dpu-demos.js` (18 live demos), `dpu-board.js`, `dpu.css` (round-1 `board.css` and `adv.css` copied in).
- Shots `shots/` (12), canvas `canvas/` (12 boards), `contact-sheet/`. The moved gantt boards are in `from-gantt-r2/` (`dash.py`, frames and shots D1–D3). Gantt itself is unchanged.
- Truth: `phase-2/truth/TRUTH-GANTT-DASHBOARD.md` §3, `TRUTH-ORDERS.md` §6 (countdown) and §7 (cloud agent jobs). Copy formats follow `FactoryChaseMessageFormatter` and `FabricChaseMessageFormatter` at laravel3.0 origin/main.

## 1. Kept and dropped

| Widget | r2 default | Where |
|---|---|---|
| Quick Order Search | **on, open, full width, at the top** | default |
| Order Countdown (days → factories → groups, Copy, due today, overdue) | **on, gets the freed space** | default |
| Overdue Components (Contacted) | **on, its own widget** | default |
| Staff Needed | **on, its own widget** | default |
| Queue Health (super admin) | off | library |
| Factory countdown | off | library (gantt r2 component, unchanged) |
| Factory load | off | library (gantt r2 component, unchanged) |
| Agent activity · today | off, new | library (★ power-up) |
| Pinned numbers (#08, adopted) | off | library (needs H01 + H06) |

## 2. Decisions on the default dashboard (D1–D5)

1. **Search on top, open.** A 40px box, with <kbd>/</kbd> to focus it. Recent shows the round-1 recently-viewed orders. Results open inline under the box with the real columns: Order # (+EXPRESS), Customer, Retailer, Status, View / Edit. Keys: ↵ ↑↓ Esc.
2. **★ Recommendation: the dashboard box and the header ⌘K / Find order are the same component.** Build one `OrderSearch` with two variants, inline here and a popover in the header, on one query hook. Today both call `admin.dashboard.quick-search` (orders only), so nothing new is needed. When one-search #05 (H04) ships, both get every type at once. Two separate search boxes would drift apart.
3. **Countdown is clearer.**
   - The 5 columns stay, future on the left and overdue on the right.
   - Each column shows the day name and date, "in N days", and a large count.
   - Each factory block has a count and its own Copy.
   - Overdue is the widest column, with a red top rule.
   - Overdue rows are sorted by days over and show the factory due date (derived from `due_at`).
   - Clicking a group opens the Gantt peek (gantt r2 K1).
4. **Stale overdue (★ option A).**
   - The 8 groups more than 30 days over fold into one line: "8 stale · 118–740 days · FRR 3 · C 2 · WZ · W · FX". They are left out of Copy while folded.
   - When opened, they show as one grey block with a factory code on each row, and they are included in Copy.
   - Options: B = grey and kept in Copy (gantt r2) · C = hidden.
5. **Copy is byte-true.**
   - Overdue: `逾期：↵FRR↵5 Days --- 4496-1-2-3…`, separator ` --- `, no trailing newline, `天` under 中文.
   - Due today: `今天要发：`.
   - Future days: `周X要交货：` then the factory, then one label per line.
   - Components: the `Hello,… Thank you.` envelope. Per supplier it holds only the lines; Copy all uses `[SUPPLIER]` sections.
   - A toast replaces `alert("Text copied")`. The block that was copied keeps a ring.
6. **Overdue Components** shows every alarm field (order, component, material, meterage, bought, expected, alerted) and **Contacted**, which stamps `contacted_at` and never removes the row. **Staff Needed** has 4 tiles with Copy each and Copy all.
7. **Only what is meaningful (D4).** With nothing to report, Overdue Components becomes one line ("All components on time"), and Staff Needed at 0·0·0·0 shrinks to a single row. Prod today really is 0·0·0·0.
8. **Phone `/m/dashboard` (D5)** is a dedicated page with one column in the person's widget order: Overdue first, stale folded, then Today, the next days, components and staff. Screen tabs sit under the app bar.

## 3. Edit mode (E1–E7)

- **E1 · Entering edit mode.** Edit turns the header into a dark edit bar: screens (drag to reorder), Add widget, Reset to role default, Cancel, Save. Each widget gets:
  - a grip
  - **Open / Collapsed** (its start state)
  - **When empty** (Always · Shrink · Hide)
  - ⋯ (density, refresh, focus)
  - × to remove
  - a resize handle

  The 12-column grid shows faintly. Widths snap to 3·4·6·8·12 columns and heights to short·medium·tall. This is a flow grid (an ordered list with spans), so the phone keeps the same order.
- **E2 · Dragging.** dnd-kit `@dnd-kit/sortable` (already in DTC). The lifted widget leaves a dashed slot and its neighbours make room. The keyboard twin is Space, arrows, Space, Esc, with a live region ("Picked up Staff Needed. Over position 2 of 4"). The resize readout says "12 columns · tall".
- **E3 · Library drawer** (440px). It lists what is on this screen, then the library with a live preview. A widget the role cannot read is never offered; Queue Health is super admin only.
- **E4 · Saved.** A second screen, "Factory wall" (Countdown + Agent activity + Factory countdown). Save is one PUT, and the toast offers Undo. If the save fails, the layout stays on this device and the screen says so.
- **E5 · Role default (super admin).** The same editor edits a role's layout, then Publish to role. A person's own layout wins; Reset to role default pulls the latest.
- **E6 · Focus mode.** One widget fills the screen with large type, the clock, and "Updated · every 30 s". F enters, Esc exits. It works in a signed-in browser. An unattended TV login is a separate decision (H31).
- **E7 · Phone edit.** A list with grips and ↑↓, start state per widget, and Add from the library. No widths on phone.

## 4. Power-ups (`/powerups/`, 18 live cards, ★ = 9)

| # | Power-up | ★ | Tag | Backend |
|---|---|---|---|---|
| 01 | Drag and drop widgets, resize them | ★ | needs backend | H01 |
| 02 | Rearrange with the keyboard (a11y) | | UI-only | (save via H01) |
| 03 | Density per widget | | UI-only | (H01 field) |
| 04 | Your own screens, in your order (reorderable tabs) | ★ | needs backend | H01 |
| 05 | Role default layouts (super admin) | | needs backend | **H29 new** `GET/PUT /admin/roles/{role}/prefs/dashboard` |
| 06 | Share a layout | | needs backend | **H30 new** `POST /admin/me/prefs/dashboard/share` + H08 picker + notifications |
| 07 | Widget library: add / remove (Queue Health, Factory countdown, Factory load live here) | ★ | needs backend | H01 |
| 08 | Collapsed by default, per widget | ★ | needs backend | H01 |
| 09 | Only show what is meaningful (Always · Shrink · Hide when empty) | ★ | UI-only | counts already in `admin.dashboard.index`; setting in H01 |
| 10 | Pinned numbers (#08, adopted) | | needs backend | H01 + H06 |
| 11 | Filter a widget: my factories / hide retired | | UI-only | (H01 field) |
| 12 | Refresh indicator + last updated, stale state | ★ | UI-only | exists: poll `admin.dashboard.index` 60 s, paused when hidden (Q2) |
| 13 | Focus mode for a wall screen | ★ | UI-only | unattended TV = **H31** display token (decision) |
| 14 | New since you last looked (+N new overdue) | ★ | needs backend | H01 `last_seen` |
| 15 | See the WeChat text before you copy | | UI-only | — |
| 16 | "Chased today" stamp on a factory | | needs backend | **H32 new** `POST /admin/dashboard/countdown/chased` |
| 17 | Agent activity · today | ★ | exists | `admin.orders.fabric-jobs.index` (cloud_jobs) + `admin.orders.print-jobs.index`, `since=today` |
| 18 | Parked: Queue Health · Factory countdown · Factory load | | exists | `admin.dashboard.index` queue_stats, `admin.orders.due`; live factory load needs per-piece start/end (gantt r2 Q5) |

★ build first: **01 · 04 · 07 · 08 · 09 · 12 · 13 · 14 · 17**. Seven of them need only H01; 09, 12 and 13 need nothing new; 17 uses ops that already exist.

## 5. Needs backend

- **H01 per-staff prefs store** (S, already filed in BACKEND-HELPERS.md, wave 1) holds everything personal under key `dashboard`: screens and their order, widgets with span, height, start, when_empty, density, filters, and last_seen. PUT is versioned (409 on a stale write). Until H01 ships, every layout choice lives in that browser only.
- **H06 counts** (S, filed) for pinned numbers.
- **New, proposed:** **H29** role default layouts (S) · **H30** share a layout (S) · **H31** read-only display token for a wall screen (decision, not drawn as default) · **H32** factory "chased today" log (S). None has been filed.
- Carried from gantt r2: the one `admin.orders.gantt-peek` read (the countdown pill opens the peek) and the factory load per-piece window.

## 6. Open questions

1. Stale overdue: A fold and leave out of Copy (drawn, ★) · B grey and in Copy · C hide.
2. Search: A one shared component, inline and header (★) · B a dashboard-only box.
3. Is Agent activity on the default for super admin only (A, ★), or for everyone (B)?
4. Role defaults: are they worth H29 now, or later once roles settle?

## 7. Truth notes

People are invented. Order ids, factory and supplier codes, countdown groups, staff, alarm and queue values are prod (Mon 19 Oct, Asia/Shanghai business day). The agent counts for today are a fixture on the real `cloud_jobs` / `print_jobs` types, labels and statuses. The pinned numbers' values are illustrative (they need H06). The factory load heat values come from the gantt r2 fixture.
