# frontend-designer — MEMORY (L1 HOT) > 8th sub-agent (S47, 2026-06-02). Role: FE **design/UX/aesthetic** cho 2 app SOLUTION_ERP. Floor FD1–FD10 (AI_INFRA canonical, KHÔNG hạ). Forked `frontend-designer.agent.template.md`. ## Role + boundary - **MINE:** FE design/UX/redesign — `fe-admin/src/**` + `fe-user/src/**` styling/component/page/design-system/a11y/responsive/micro-interaction. Design-by-code (React/Tailwind/shadcn), KHÔNG Figma. - **NOT MINE:** BE/DB/business-logic (implementer-backend) · cookie-cutter mechanical mirror theo spec (implementer-frontend — **KHÔNG double-touch cùng file UI**) · test (test-specialist). - **store_memory GỠ** (broadcast 2026-06-02) → ghi finding/token/component vào FILE NÀY; em main + re-index đưa vào RAG. ## SE design-system (FD1 — DÙNG, KHÔNG reinvent) — VERIFIED S47 - Brand primary **`#1F7DC1`** · font **Be Vietnam Pro** (Vietnamese diacritics) · Tailwind tokens · ERP shell (TopBar + Bell + UserMenu). - ⚠️ **Token source = Tailwind v4 CSS-first** (NO `tailwind.config.js` file — template path stale). Tokens live in `fe-user/src/index.css` `@theme{}` block (mirror `fe-admin/src/index.css`). Read TRƯỚC khi build. - Brand scale `--color-brand-50..900`; **`--color-brand-600 = #1f7dc1`** (exact logo). Accent red `--color-accent-500/600` (from ® mark). Be Vietnam Pro + JetBrains Mono via Google Fonts `@import` in index.css. body 14px / lh 1.55 / letter-spacing -0.003em. - UI primitives are **hand-rolled cva** (NOT vanilla shadcn copy): `fe-user/src/components/ui/{Button,Input,Label}.tsx`. Button variants primary/secondary/outline/ghost/danger × sm/md/lg; focus-visible ring brand-500 + disabled:opacity-50 already wired. Input has focus-visible border-brand-500 + ring. REUSE these, don't reinvent. - Stack: React 19 + Vite 8 + TS 6 + TanStack Query + lucide-react + sonner. Node v22 local (engines `>=20`). - UI 100% tiếng Việt · Named export (trừ App) · TS6 `const X = {...} as const` thay enum · PageHeader chỉ {title, description, actions} · Duplicate 2 app CÓ CHỦ ĐÍCH (§3.9). ## FD2 visual-verification rig (SE-specific) — ✅ VERIFIED RAN end-to-end S47 - Dev: `cd fe-admin && npm run dev` → :8082 (proxy /api→:5443) · `cd fe-user && npm run dev` → :8080. - Auth: ERP behind login — token localStorage `solution-erp-admin-token` / `solution-erp-user-token`. Authed page screenshot cần API+SQL chạy + login fixture (seed JWT). Public `/login` chụp trực tiếp. - **PROVEN rig** (`webapp-testing` skill = Python Playwright, NOT npm @playwright/test): - Bash tool is **POSIX bash** despite env "PowerShell" note → use `cd "abs/path"` (NO `cd /d`). Forward-slash Windows paths work. - Chromium for Testing already installed (`C:\Users\pqhuy\AppData\Local\ms-playwright\chromium-1223`). Python 3.11 + `playwright` binding present & drives headless OK. NO install needed. - Run pattern: `python /scripts/with_server.py --server "npm run dev" --port 8080 --timeout 90 -- python my_shot.py` (helper starts/stops dev). Write my_shot.py in fe-user dir, **delete after** (throwaway, not app code). - Screenshot: `browser.new_page(viewport={w,h}, device_scale_factor=2)` → `page.screenshot(full_page=True)` → **Read PNG** to NHÌN. - 🪲 **2 Vite-dev gotchas (cost me 2 failed runs):** (1) `wait_until="networkidle"` NEVER fires — Vite HMR websocket stays open → use `domcontentloaded` + `wait_for_selector("form")`. (2) FIRST goto after cold server triggers Vite dep-optimize compile (>15s) → add a **warm-up goto with 60s timeout** before the viewport loop, else first viewport times out. - 🪲 (3) **Authed-page (Dashboard…) S55 BLOCKER:** `dotnet run` API binds **HTTPS :5443** + HTTP :5444 (Program.cs overrides `ASPNETCORE_URLS`), nhưng `vite.config.ts` proxy target = `http://localhost:5443` → protocol mismatch → /api login fail → kẹt /login. ĐỂ chụp authed: temp-set proxy `https://localhost:5443` (`secure:false` sẵn) + restart Vite + **REVERT sau**; HOẶC run API HTTP-only. + Dashboard = ProtectedRoute (cần JWT) → Playwright login THẬT (fill `admin@solutions.com.vn`/`Admin@123456` + submit + wait url≠/login). S55 rig này chặn cả designer + em main → **đáng tin nhất = deploy prod rồi login thật xem authed pages** (đừng vật lộn dev-rig cho authed screenshot). - Fallback khi stack chưa chạy: static component preview / screenshot `/login` — **KHÔNG bỏ soi** (FD2 cấm ship-unseen). ## Component inventory (built/verified — chống reinvent) - _(**3 shared UI E-Office (S69): `ui/PageHeader` giàu (eyebrow/icon/accent) + `ui/KpiCard` filter-chip + `ui/WidgetCard`** — accent map, a11y Enter/Space, gotcha-66 `text-white!` trên nền gradient. verbatim → `archive/2026-06.md` §"S69 … 3 shared UI")_ - _(**`pages/office/OfficeDashboardPage.tsx` (S69)** — E-Office landing PURO, compose 3 widget, reuse hook verbatim 0 API mới. verbatim → `archive/2026-06.md` §"S69 … OfficeDashboardPage")_ - `fe-user/src/pages/LoginPage.tsx` — login (public, no auth). Layout: gradient bg + 2 blur blobs + centered `max-w-md` card (bg-white/90 backdrop-blur) → logo / brand eyebrow / subtitle / Email+Mật khẩu / full-width Đăng nhập. Uses ui/{Button,Input,Label}. Solid baseline; nearly identical in fe-admin (mirror candidate). - `fe-user/src/pages/hrm/EmployeesListPage.tsx` — **2-panel master-detail HRM (S66 refine, was 3-panel S65)**: shell `lg:grid-cols-[22rem_1fr] xl:grid-cols-[24rem_1fr]`. **CỘT TRÁI** = `
` chứa Org-tree (TRÊN, `lg:max-h-[44%] lg:shrink-0`, cuộn riêng) + List+filter (DƯỚI, `flex-1`, cuộn riêng). **CỘT PHẢI** = Detail 5-tab (flex-1, rộng). 1000 LOC) = ONE atomic `Write` cả-file (lands-fully-or-errors, no half-break) + **EMIT change-list + build-verdict TRƯỚC khi vào FD2 screenshot loop** (2× truncate liên-tiếp CÙNG điểm rig-entry — S55/S58, em-main proxy recover). Truncate giữa-run → build ×2 verify. - **Tailwind v4 accent-stop:** teal/violet/amberx/greenx CHỈ có stop 50/100/500/600/700 — **KHÔNG -800** → head/value dùng -700 (brand -800 OK). Dùng -800 = silent no-class (build PASS, phải soi dist CSS). Rail pseudo cần `before:content-['']` else ::before không render box. - **Authed-rig gotcha #3:** dev-rig chặn authed ProtectedRoute (API HTTPS :5443 ⟂ vite proxy HTTP → login fail kẹt /login) → **verify authed pages qua DEPLOY prod login thật**, đừng vật-lộn dev-rig. Public /login chụp trực-tiếp OK. - **Lucide alias-dodge:** icon từ export-aggregation-line (`SendHorizonal`) / mojibake token (`网络Placeholder` autocomplete) → dùng proven-safe export (`Send`), node-check icons trước build. ## Activity log - **S174 (2026-08-05) AUDIT style KHKK(GĐ2) ⟂ Duyệt NCC(GĐ1) — ensemble 5 lane CÙNG 1 VAI qua `/fable-clone`, 5/5 xong 0 chết, 755K tok/147 tool-use/~17′.** *(Entry on-behalf bởi lead @pause cổng C2 — VERIFY từ 5 sub-file trên đĩa + tự re-đo 2 claim nặng nhất.)* Run `wf_016b1bed-b85`, artifact `runs/2026-08-05-S174-khkk-style-audit/sub-frontend-designer-L1..L5.md` (34+41+30+33+32 KB) + `spec-khkk-style-dong-bo-05-08-2026.md`. **Lăng-kính:** L1 panel-duyệt · L2 panel-list · L3 host · L4 cây · L5 nội-dung. **Verdict:** L1 15 lệch (13 bê-thẳng) · L2 CHƯA-PASS 13 delta + 3 trục rubric đỏ · L3 KHỚP-MỘT-PHẦN · L4 SHIP-SPEC-READY · L5 6 P0 + 8 P1 + 3 P2. 🔴 **3 phát hiện owner KHÔNG nêu mà nặng hơn phần lớn danh sách owner nêu:** (a) **LỖI THẬT** `KhkkWorkflowPanel:501` tải file bằng `` trần ⇒ JWT chỉ gắn qua interceptor axios (`lib/api.ts:18`) ⇒ endpoint `[Authorize]` ăn **401, nút không chạy** — lead verify bằng đối-chứng `responseType:'blob'` ở PE `:331`; (b) vỏ `card-accent` bọc panel KHKK ⟂ PE panel TRẦN = thứ làm 2 bên "nhìn khác hệ" TRƯỚC mọi mục owner kê; (c) `