# HANDOFF: RJ Laravel Admin, round-1 design pack (PIÑA → frontend team)

**Client:** RJ, internal (PIÑA `brand-006-rj-laravel-admin`) · **Handed off:** 2026-10-18 (round-1 snapshot) · **Owner:** Frank
**Folder (command-center repo):** `projects/pina/brands/brand-006-rj-laravel-admin/` · the pack is `pack/`
**Front door (every live board, with its status):** https://pina-brand-006-rj-laravel-admin.pages.dev/ · phone: `/m/`
**Target stack:** Next.js App Router + React 19 + TypeScript + shadcn/ui (Radix) + Tailwind 3.4 over CSS-variable tokens, sharing one kit package `@rj/admin-kit` with the DTC admin.

---

## Paste-ready paragraph for the team

> PIÑA has designed the new RJ Laravel admin (`admin.rjmtm.com`, staging `stg-admin.rjmtm.com`), the one that replaces the old Blade pages and talks to Laravel only through the documented admin REST API. Frank picked the direction, "4b·R": a white header with the white "RJ HQ · Master admin" corner, the exact DTC navy sidebar (`#0E1729`), a 76px collapsed rail with a label under every icon, and ultra-compact density by default (12.5px body, 30px rows; comfortable is a per-person token mode). It is the F1 sibling of the DTC admin: same tokens and component vocabulary, so both admins share one kit package, `@rj/admin-kit`. The DTC admin uses the same kit with `data-theme="dtc"` (Midnight green). All 325 live pages are mapped in **PAGE-MAP.md**, the integration checklist: one row per page → archetype and layout → the hero screen to copy → kit components → the exact API `operationId`s → needs-backend items → permission → phone mode. Build in this order: **the kit package → the shell → Orders → Tickets → Designs → Pricing → the archetype waves 1–4.** Most pages are built from 11 approved archetypes. Orders, the order page, Tickets, Designs (every designs page) and Pricing are flagships with their own design rounds; they are still in review, so start them last among the foundations and re-check the board before you build. **Invent nothing:** real statuses, real fields, real buttons only. The truth docs are the source, and anything beyond today's admin is a tagged proposal in **PROPOSALS.md**. Needs-backend items become `api-request` issues in `RJmtm/newadmin-api-kit` (listed below, ready to file). Until one is closed, draw the "needs backend" ghost and never a working control.

---

## 1. What to build first (recommended order)

| # | Build | From | Gate before starting |
|---|---|---|---|
| 1 | **`@rj/admin-kit` package**: base tokens + Laravel theme + DTC theme, the shadcn / Radix primitives, the 36 F1 composites | `tokens.css`, `CONTRACT.md`, kit boards | repo location is still open (default `RJmtm/admin-kit`, see §6); start in a scratch repo if it is not answered |
| 2 | **Shell**: permission-shaped from `admin.me.show` + `admin.me.menu`; 76px labelled rail ↔ 232px sidebar; T-d mega flyout; T-f breadcrumb dropdowns; Find order; Jobs list; bell; globe EN ↔ 中文; clock → timezone; ⌘K; Clerk sign-in, signed-out, expired session; `/m/` phone shell | kit `shell`, `job-tray`, `locale-tz`, `combobox`; `reference/MENU-TECHNIQUES.md` | none |
| 3 | **Orders flagship**: `/admin/orders` + `/admin/orders/{order}` | https://orders.pina-brand-006-rj-laravel-admin.pages.dev/ · `reference/flagships/ORDERS-R1.md` · `reference/TRUTH-ORDERS.md` | round 2 in progress: re-check the board when it lands |
| 4 | **Tickets**: `/admin/tickets`, `/admin/tickets/new`, `/admin/tickets/{ticket}` | https://tickets.pina-brand-006-rj-laravel-admin.pages.dev/ · `TICKETS-R1.md` · `TRUTH-TICKETS.md` | round 2 in progress |
| 5 | **Designs**: all 25 designs-module pages | https://designs.pina-brand-006-rj-laravel-admin.pages.dev/ · `DESIGNS-R1.md` · `TRUTH-DESIGNS.md` | round 2 in progress; 21 of the 25 pages are not drawn yet (queued for designs round 2) |
| 6 | **Pricing**: the pricing module | https://pricing.pina-brand-006-rj-laravel-admin.pages.dev/ · `PRICING-R1.md` · `TRUTH-PRICING.md` | round 2 in progress (restructured into two equal parts: fabric combination pricing and design pricing) |
| 7 | **Archetype waves** 1 → 4 (every non-flagship row of `PAGE-MAP.md`) | https://archetypes.pina-brand-006-rj-laravel-admin.pages.dev/ · `reference/ARCHETYPES.md` | approved (decision B) |

Waves: 1 orders · designs · tickets (74 pages) → 2 users · access · products · pricing · billing (68) → 3 materials · fabrics · factory · shipping · vision-checks (102) → 4 content · ops · micro-apps · wechat · ai · settings · dashboard · print-studio (81). `/admin/gantt` waits for the gantt pick (§6).

## 2. The stack

Decided by Frank (2026-10-18: "I have absolutely no problem with that stack whatsoever"). Same majors as the DTC admin so the kit has one peer set: Next 15.5, React 19, TypeScript 5, Tailwind 3.4, `@tanstack/react-table` 8.21, `lucide-react` 0.469. Full package map with licences in `reference/STACK-AND-PACKAGES.md` §3 (all MIT / ISC / BSD / Apache; no paid licence). Fixed behaviours, from the backend rulings:

- **Dedicated `/m/` routes.** Every page with a phone answer has its own `/m/…` route and view; only the view layer forks. Middleware routes by `Sec-CH-UA-Mobile` / user agent with an `rj_surface` cookie, never by viewport width. Pages with no phone view → `/m/not-on-phone?to=…`.
- **Density mode.** `data-density="compact|comfortable"` on `<html>`; Laravel defaults to compact, the phone shell is comfortable.
- **i18n en / cn and per-staff timezone.** `next-intl` without locale URL prefixes; locale and timezone come from `PUT /admin/me/preferences` (T001 Q25). The API sends UTC; format in the staff zone.
- **Polling every few seconds** for jobs, imports, exports, print runs, vision re-runs (T001 Q2). No websockets.
- **Server PDFs via signed links** (T001 Q26): prepare → open in a new tab. No client PDF library.
- **Typed confirm** for the scary actions (T001 Q14), inside the confirmation ladder.
- **Permission-shaped shell** from `/admin/me/menu`; a control the role cannot use is absent.
- **Bulk in batches of 100** (T003 #13) with batch progress and Stop.
- **API** only through `@rjmtm/newadmin-client` wrapped in query hooks. The hosted mock allows `localhost:5173`; run `next dev -p 5173` or add `:3000` to its origins.
- **24 power-ups** adopted (listed in `DESIGN-SYSTEM.md` §4.10).

## 3. Where everything is

### Live (hosted)

| What | Link | Status |
|---|---|---|
| **Front door** (all of the below, with status) | https://pina-brand-006-rj-laravel-admin.pages.dev/ · `/m/` | live |
| Direction (final 4b·R + canvas; rounds 1 and 2) | https://ladder.pina-brand-006-rj-laravel-admin.pages.dev/final/ · `/final/canvas/` | decided |
| F1 component kit (36 families, desktop + phone) | https://kit.pina-brand-006-rj-laravel-admin.pages.dev/families/ · `/families/m/` | decided (v1) |
| Archetypes (sheet + canvas) | https://archetypes.pina-brand-006-rj-laravel-admin.pages.dev/ · `/canvas/` | approved for non-flagship pages |
| Flagship: Orders + order page | https://orders.pina-brand-006-rj-laravel-admin.pages.dev/ · `/canvas/` | r1 accepted with defaults, needs more work; round 2 in progress |
| Flagship: Tickets | https://tickets.pina-brand-006-rj-laravel-admin.pages.dev/ · `/canvas/` | round 2 in progress |
| Flagship: Designs | https://designs.pina-brand-006-rj-laravel-admin.pages.dev/ · `/canvas/` | round 2 in progress |
| Flagship: Pricing | https://pricing.pina-brand-006-rj-laravel-admin.pages.dev/ · `/canvas/` | round 2 in progress |
| Gantt (3 directions) | https://gantt.pina-brand-006-rj-laravel-admin.pages.dev/ · `/canvas/` | pick deferred to the end |
| Power-ups (24) · advanced | https://powerups.pina-brand-006-rj-laravel-admin.pages.dev/ · `/advanced/` | decided · advanced awaiting picks |
| Menu techniques | https://menu.pina-brand-006-rj-laravel-admin.pages.dev/ · `/m/` | decided (T-d + T-f) |

When a flagship's round 2 lands, its branch serves round 2 at `/` and round 1 at `/r1/`; the URLs above do not change.

### In the repo (paths relative to the brand folder)

| What | Path |
|---|---|
| **Integration checklist** (start here) | [`PAGE-MAP.md`](PAGE-MAP.md) · machine copy [`page-map.seed.json`](page-map.seed.json) |
| Design system, one file (foundations · components · patterns · implementation) | [`DESIGN-SYSTEM.md`](DESIGN-SYSTEM.md) |
| Tokens (source of truth) · W3C tokens (both themes + comfortable mode) | [`tokens.css`](tokens.css) · [`tokens.json`](tokens.json) |
| Base styles of the kit | [`base.css`](base.css) |
| Component spec (name, props, states, shadcn / Radix mapping, package) | [`CONTRACT.md`](CONTRACT.md) · [`KIT-CHANGELOG.md`](KIT-CHANGELOG.md) |
| Proposals (82, each with a recommended default) | [`PROPOSALS.md`](PROPOSALS.md) · [`PROPOSALS.json`](PROPOSALS.json) |
| Needs-backend issues, ready to file | [`API-REQUESTS.md`](API-REQUESTS.md) |
| Backend helper build order (H01–H28) | [`BACKEND-HELPERS.md`](BACKEND-HELPERS.md) |
| Drop-in files (`globals.css`, `tailwind-preset.ts`, `components.json`) | [`implementation-files/`](implementation-files/) |
| Truth docs, flagship R1 notes, archetypes, stack, power-ups, menu | [`reference/`](reference/) |
| Pack gate report | [`pack-gate.txt`](pack-gate.txt) |
| Source boards (build scripts per board) | `phase-1/kit/src/`, `phase-2/archetypes/src/`, `phase-3/flagships/<area>/src/` |
| Rebuild the pack | `python3 phase-3/pack-src/build_pack.py` (page map: `python3 phase-3/waves/build_page_map.py` then `check_page_map.py`) |

## 4. How to read the page map

Each row of `PAGE-MAP.md` is one live page (325; 2 retired pages are listed but not designed):

- **arch·layout**: the archetype and its locked layout (A01·a full-width table, A02·a tabs, A03·a section nav left, A06·a table of runs, A11·a 3-pane). `★` = flagship.
- **hero**: the screen to copy. Non-flagship rows copy the archetype hero board; flagship rows (34: orders 2 · tickets 3 · pricing 4 · designs 25) copy `phase-3/flagships/<area>/`. Designs rows marked "queued for designs round 2" are flagship but not drawn yet: do not build them from the generic archetype.
- **overrides**: what the page adds on top of its archetype.
- **components**: exact kit names (`M01`–`M17` are the new components: job tray, matrix editor, gantt, document link + cloud print, diff viewer, split pane, bilingual pair, date-time, locale / timezone, photo lightbox, JSON viewer, cron builder, QR, sortable list, tree view, rich text, measurement grid). The shell components are on every page and not repeated.
- **API ops**: the catalogue `operationId`s the page calls (all exist in the spec; 1,077 of 1,083 actions are mapped).
- **needs-backend**: `PR-…` proposals that touch this page. Draw the ghost, do not wire.
- **perm**: the route permission (or the ops' `x-permission`). The spec over-states the orders / tickets list requirements (PR-082).
- **phone**: `dedicated` (real `/m/` view) · `read-mostly` (simple read-only `/m/` view) · `desktop-only-notice` (fallback page).
- **partial actions**: were PARTIAL on 2026-10-12; verify the fields on staging before building that action.

## 5. Needs-backend list (49): file as `api-request` issues in `RJmtm/newadmin-api-kit`

**Not filed yet.** Each item has a ready-to-paste issue block (title, label `api-request`, ask, pages, evidence) in [`API-REQUESTS.md`](API-REQUESTS.md). File in the backend helper order (`BACKEND-HELPERS.md`): **H01 per-staff prefs store** and **H02 record history** first, because each unlocks several items.

| # | Issue title | Helper | Area |
|---|---|---|---|
| PR-001 | Per-staff prefs store (saved views, column presets, density, recent/pinned across devices, My home, import mapping memory) | H01 | shell |
| PR-003 | Record-wide history / activity / audit store (activity panel, time-travel, design + pricing undo, bulk-run before-values) | H02 | shell |
| PR-005 | One search across orders, accounts, fabric codes, tickets, designs (⌘K beyond orders) | H04 | shell |
| PR-006 | Say it in ⌘K (sentence -> filter or action) | H05 | shell |
| PR-007 | Counts for the filtered set (totals strip) | H06 | orders |
| PR-008 | Who else is here (presence + soft edit lock) | H07 | shell |
| PR-009 | Names-only admin picker (for @mentions and ticket assignee) | H08 | shell |
| PR-010 | Comments and @mentions on any record | H10 | shell |
| PR-011 | Watch a record -> notification inbox | H11 | shell |
| PR-012 | While you were away (shift hand-over digest) | H12 | shell |
| PR-013 | Stuck-in-phase timers (phase ages + targets) | H09 | orders |
| PR-014 | Why is this order here? (one composed explain read) | H13 | orders |
| PR-015 | Restore one value from history | H14 | shell |
| PR-016 | Do it later (scheduled actions; allow-listed, never money) | H15 | shell |
| PR-017 | Dry-run impact preview on the four bulk writes | H16 | users |
| PR-018 | Undo a whole bulk run (10-minute window) | H17 | shell |
| PR-020 | See the admin as someone else's role | H20 | access |
| PR-021 | Paste from Excel into an import (JSON rows on import preview) | H21 | materials |
| PR-022 | Trends inside the table (metric series sparklines) | H22 | users |
| PR-023 | Scan a QR to open the record | H23 | shell |
| PR-024 | Keeps working when Wi-Fi drops (Idempotency-Key honoured on floor writes) | H24 | vision-checks |
| PR-025 | Ping me when it's done (Web Push) | H25 | shell |
| PR-026 | Ticket summary + suggested next step (AI summary mode, explicit button) | H26 | tickets |
| PR-027 | Anomaly flags on orders | H19 | orders |
| PR-028 | Health strip for super admins | H27 | ops |
| PR-029 | Out of stock? closest cloths in stock | H28 | fabrics |
| PR-033 | Cancel a queued print job (G1) | — | orders |
| PR-034 | Resolve several vision results at once (G2) | — | vision-checks |
| PR-035 | Ticket assignee + 'Mine' view + routed notifications (G3) | — | tickets |
| PR-036 | Internal (staff-only) ticket note (G4) | — | tickets |
| PR-037 | Persist the last AI suggestion per ticket (no re-billing on reopen) | — | tickets |
| PR-039 | CN labels for ticket statuses, severities and categories | — | tickets |
| PR-040 | Attachment count on ticket list/show payloads | — | tickets |
| PR-042 | Order filter on the tickets index | — | tickets |
| PR-043 | Order status-history read (Activity tab) | — | orders |
| PR-057 | gantt-grid rows: factory_due_at + current_step | — | orders |
| PR-058 | gantt-grid rolling window (from/to across months) | — | orders |
| PR-059 | Express flag on gantt rows | — | orders |
| PR-060 | Factory capacity per day | — | factory |
| PR-061 | /orders/due horizon beyond 3 days | — | orders |
| PR-062 | Design create silently drops the surcharge (extra_meter) | — | designs |
| PR-063 | Camera frame and Supplier on the design create form | — | designs |
| PR-064 | 'Retailers carrying this design / priced?' panel on the design page | — | designs |
| PR-066 | Align design 'info' validation (max:1000 on the edit path) | — | designs |
| PR-068 | Ungated web pricing writes | — | pricing |
| PR-070 | Retailer pricing cell write by ids, not localized display name | — | pricing |
| PR-072 | Menu badge counts (optional integer badge per link) | — | shell |
| PR-073 | Backfill cn labels for the menu (90 missing)  | — | shell |
| PR-082 | Spec permission metadata drift on orders/tickets lists | — | orders |

## 6. Open decisions for Frank

Every one has a recommended default; that is what ships if nobody answers. Do not build the affected control until it is answered or the default is confirmed.

| Area | Open | Recommended default |
|---|---|---|
| **Gantt** | Direction pick (PR-056): G1 Ledger · G2 Floor · G3 Countdown | **G1 Ledger**, with G2 as its Factories toggle and G3 as the dashboard countdown widget. Pick deferred to the end of the run |
| **Kit repo** | Where `@rj/admin-kit` lives (PR-075): A inside `rj-dtc` · B own repo · C inside `newadmin-api-kit` | **B, `RJmtm/admin-kit`** (neither admin owns it) |
| **Orders** (r1 accepted with defaults; 12 questions, PR-044 … PR-054) | print button default, resolve hold on the order page, saved-views scope, customer details, tab set, measurement-check values, complete across pages, hold without ticket, default view, sort, void on the order page, product type column | the drawn option for each (e.g. print opens Cloud print; 10 tabs; default view Active; personal saved views only in v1; hold always keeps its ticket) |
| **Tickets** (12 questions, `TICKETS-R1.md`) | default view, Re-Open in "Needs us", thread order, Undo on the status toast, typed confirm for wallet money, AI cost note, hold on new ticket, open-order behaviour, Technical Support card, wallet on no-order tickets, internal note, assignee | the ★ pick for each (e.g. default "Needs us"; oldest-first thread; wallet keeps the real two-step; internal note needs backend) |
| **Designs** (12 questions, `DESIGNS-R1.md`) | swatch rows on the edit page, System vs Printer card, index status column, saved views, surcharge drop on create (G1), keyboard grid, bulk paste, OUT-OF-STOCK prefixes, camera frame + supplier on create, blocker switch, Bulk Hub row actions, phone | the drawn option for each; plus the 21 undrawn designs pages (designs round 2) |
| **Pricing** (13 questions, `PRICING-R1.md`) | who can open Pricing, save model, decimals, 0 on fabric pricing, ladder thresholds, bulk on the fabric grid, import preview, settlement currency check, column titles, excess label, design pricing CSV, Pattern Design Add-Ons link, phone | the bold option for each (e.g. super admin only; one Submit + save bar; client-side import diff) |
| **Power-ups** | Advanced round (29 patterns, PR-032) | adopt the 10 ★ |
| **Other needs-a-decision** | PR-002 shared team views · PR-019 maker-checker · PR-038 change order on a ticket · PR-055 rename Fabric Purchase Jobs → Agent jobs · PR-067 retire popup bulk routes · PR-069 design pricing CSV · PR-074 menu regroup (parked) · PR-079 posts / watermark-text | as written in `PROPOSALS.md` |

Round 2 of the four flagships is running now and may close some of these; the front door shows the current status.

## 7. Rules for the build

- **Invent nothing. The truth docs are the source.** Only real statuses (11 order, 6 ticket), real fields, real buttons, real codes: order ids are bare numbers (`4521`, pieces `4521-1`), no letter prefixes; factories as codes. If a control has no catalogue operation, it is a proposal, not a feature.
- **Permission-shaped.** Hide what a role cannot use; "Not available to your role" only where hiding would confuse.
- **Desktop and phone are separate views.** On phone, tables become card lists and sheets come from the bottom; never squeeze the desktop layout.
- **No real customer data on any public URL**, including your preview deploys. Use the mock and the flagship fixtures.
- **Don't redesign the printed PDFs or the Print Studio canvas**; design their launchers and job states only.
- **Ignore the board chrome** (label chips, annotation panels, the purple "proposal" and amber "needs backend" tags). They are review aids, not product UI; in the product, needs-backend shows as the kit's ghost state.

## Not in git (too heavy or private)

- Screenshots over 200 KB (`shots/`, contact sheets) and the canvas runtime copies (`canvas/artifact-type/`). The hosted boards above are the record; rebuild with each board's `src/*build*.py`.
- `phase-2/truth/shots/`: screenshots of the live staging admin with real data. Private: kept on the author's disk only, never committed or deployed.
