Closeout S65 (~6 deploy prod-verified, anh + anh Kiệt FDC UAT realtime): - STATUS/HANDOFF S65 (Mig 52 · 88 bảng · 263 test · 65 gotcha · menu 53 · bundle admin BDwV5d0X / user DbVv6rsf Run #295) + session log #289→#295. - gotcha #65 (build csproj con ≠ dotnet build slnx gồm tests → CS7036 Run #291 FAIL-gated; fix +trailing-optional sweep). - CLAUDE.md root Mig 50→52 + PE row +Mig 52. - Harvest: H2 GATE 2-MISS closed — 2 on-behalf record (PE-Workflow FE + reviewer empty-return #53) → impl-frontend + reviewer agent-memory. H1 tooling CLEAN (roster/skill/plugin 11/6/18). - Memory (user-global): +feedback_workflow_fanout_reliability. Carry-P1: cicd-monitor L1 82KB curate-L2 · mirror Employee page→fe-admin · test-after (HoSoLink/ParentId/HRM-perm). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
45 lines
14 KiB
Markdown
45 lines
14 KiB
Markdown
# 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 <skill>/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)
|
||
- `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** = `<div flex flex-col gap-4>` 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). <lg → 1-col (tree→list→detail) + mobile tree-toggle `treeOpenMobile` (tree `hidden`→`flex`). Org tree = recursive `TreeNode` consume `GET /api/departments/tree` (DepartmentTreeNode {id,code,name,parentId,directEmployeeCount,totalEmployeeCount,children}); gốc "SOLUTION COMPANY" (`companyOpen`) → `pickDept(null)`=all; `CountBadge` (totalEmployeeCount, active=brand-600 fill) → `deptId` URL param. Detail = avatar header (`.app-gradient-brand` + initials-in-rounded-2xl) + 5-tab nav (Tổng quan/Thân nhân/Trình độ/Kinh nghiệm/Hợp đồng) count pills + brand underline. **Accent system (S66 việc 2+3):** `type Accent='brand'|'teal'|'violet'|'amberx'|'greenx'` + `ACCENT` map (chipBg/chipFg/head/rail/labelText). `Card` nhận `accent` prop → `.icon-chip` tinted (`--chip-bg`/`--chip-fg` inline) + heading `text-{x}-700` + left rail pseudo `before:content-[''] before:w-1 before:bg-{x}-500` (clip qua overflow-hidden). `Field` label = `text-{x}-700` uppercase semibold (was slate-400), value = `font-medium text-slate-900` (was slate-800). OverviewTab: 1 accent/card (Thông tin chung=brand, Sức khoẻ/Lương=greenx, Liên hệ/Ngân hàng=teal, Giấy tờ/Đoàn thể=violet, Công việc=amberx). Tab-body sections: family=violet, đào tạo=teal, kỹ năng=greenx, công tác=amberx, hợp đồng=brand. ⚠️ **accent palettes chỉ có stop 50/100/500/600/700 — KHÔNG -800** → head dùng -700 (else Tailwind v4 silent no-class). Reusable: `Avatar`(hash 5 gradients + dim), `CountBadge`, `Card`(+accent), `Field`(+accent/mono/icon/full). **ALL 5 satellite CRUD + 15 satellite api endpoint (+ top-level del + 3 reads) + 3 query keys preserved verbatim** (grep+tsc verified, layout/style-only). fe-admin NOT mirrored (separate pass).
|
||
|
||
## Anti-slop catches + rubric verdicts
|
||
- **LoginPage (S47): rubric PASS.** Anti-generic ✓ (brand #1F7DC1 NOT default-blue, no emoji, lucide-ready, purposeful palette). Fix applied: subtitle "Đăng nhập để tiếp tục" `text-slate-500`→`text-slate-600` (borderline ~4.6:1 over translucent card → solid ~7.5:1, FD5 contrast floor). 1-line, no layout shift, on-scale (FD1). Screenshots: `/tmp/fd2-login-shots/login-{before,after}-{mobile-375,desktop-1440}.png`.
|
||
- ⚠️ **fe-admin parity follow-up:** same subtitle likely `text-slate-500` in fe-admin LoginPage — apply same bump next fe-admin touch (did NOT touch fe-admin this run; scope-disciplined).
|
||
- Minor noted (NOT fixed, out of bounded scope): 2 `blur-3xl` blobs barely visible at 1440 = render cost ~0 payoff; eyebrow `tracking-[0.2em]` heavy. Candidates if login redesign requested.
|
||
|
||
## Activity log
|
||
- **S66 (2026-06-16) HRM Hồ sơ Nhân sự fe-user REFINE từ eoffice LIVE (3 việc) — layout 3-cột→2-cột + tô màu detail:** anh góp ý sau khi xem prod. **Việc 1 (layout):** 3-cột-ngang `[tree 244 | list 352 | detail 1fr]` → **2-cột** `lg:grid-cols-[22rem_1fr] xl:[24rem_1fr]`: CỘT TRÁI = `<div flex flex-col gap-4>` ôm tree (TRÊN, `lg:max-h-[44%] lg:shrink-0`, overflow-auto) + list+filter (DƯỚI, `flex-1`, overflow-auto) — mỗi panel cuộn độc lập; CỘT PHẢI = detail (flex-1, rộng hơn nhiều, đỡ chật). <lg vẫn 1-col tree→list→detail + giữ nguyên `treeOpenMobile` toggle. **Việc 2+3 (màu detail):** thêm `ACCENT` map 5 tone (brand/teal/violet/amberx/greenx) → `Card` prop `accent` tô icon-chip nền nhạt (`--chip-bg/--chip-fg`) + heading `text-{x}-700` + rail trái pseudo-element; `Field` label uppercase `text-{x}-700` semibold (was slate-400 đơn điệu) + value `font-medium text-slate-900`; mỗi card/section gán 1 accent → có màu rõ nhưng tinh tế, brand #1F7DC1 + Be Vietnam Pro + avatar gradient brand GIỮ. **Strategy chống truncation #53 = ONE atomic `Write` cả file** (1556 LOC) → emit change-list + build status SỚM. **2 self-caught bug TRƯỚC build:** (1) `text-{teal,violet,greenx}-800` — accent palettes KHÔNG có stop -800 (chỉ 50/100/500/600/700) → Tailwind v4 silent no-class → đổi head sang -700 (all AA on white); (2) rail pseudo thiếu `before:content-['']` → ::before không render box → thêm. `npm run build` (tsc -b strict + vite v8) **PASS 0 TS err, 495ms** (warning @import-order + chunk-size = pre-existing, không phải mình). **5 satellite CRUD + 15 satellite api endpoint + top-level del + 3 reads + 3 query keys (employees-list/employee-detail/departments-tree-hrm) + cây SOLUTION COMPANY + 5 tab + search/filter preserved VERBATIM** (grep: 15 satellite api.post/put/delete + 3 queryKey + 5 form fns; tsc type-checks mọi payload shape = wiring bất biến). FD2 authed-screenshot SKIPPED per task instruction + gotcha #3 (rig chặn authed ProtectedRoute; anh xem qua deploy) → structural verify thay thế. fe-admin + BE NOT touched, no commit (em main commits). Tag [s66, hrm-2col-refine, eoffice-ref, accent-system, atomic-write-antitrunc, crud-preserved, build-pass, tailwind-v4-stop-gotcha].
|
||
- **S65 (2026-06-16) HRM Hồ sơ Nhân sự fe-user → 3-panel master-detail NamGroup-ref:** RESTRUCTURE `EmployeesListPage.tsx` (1201→~1140 LOC) — 6 `<details>` → [Org tree | List | Detail 5-tab]. **Strategy chống truncation #53 = ONE atomic `Write` (cả file)** thay piecemeal Edit (atomic Write either fully-lands or errors, KHÔNG half-break) → emit change-list TRƯỚC build → DID BOTH Part A (avatar header+5 tab+section→tab redistribution) + Part B (org tree panel) trong 1 pass, không phải defer B. Org tree consume `/departments/tree` verified BE-side (DepartmentFeatures.cs DepartmentTreeNodeDto, controller `[HttpGet("tree")]`, class-Authorize only). Foundation màu mới DÙNG: `.app-gradient-brand` header / `.icon-chip` / accent palette teal/violet/amberx/greenx (avatar tones) — brand #1F7DC1 + Be Vietnam Pro KEPT. **5 satellite CRUD + 16 api endpoint + query keys preserved VERBATIM** (grep-verified: 16 api.post/put/delete identical payload shape, 5 form fns intact). `npm run build` (tsc -b strict + vite) **PASS 0 TS err, 6.13s**. 1 self-caught bug: typo garbage token `网络Placeholder` trong lucide import (mojibake autocomplete) → removed, all 21 icons valid (node-checked). FD2 authed-screenshot SKIPPED per explicit task instruction + gotcha #3 (rig blocks authed; anh xem qua deploy) — did static structural verify instead (grep endpoint/key preservation). fe-admin NOT touched (mirror = separate pass), no commit. Tag [s65, hrm-3panel, namgroup-ref, atomic-write-antitrunc, crud-preserved, build-pass].
|
||
- **S58 (2026-06-11) fe-user redesign theo UI/UX guide AI_INFRA canonical — KEEP brand [em main proxy — truncated #53 giữa FD2 screenshot, 2nd consecutive]:** Mirror design-system fe-admin S55 → 14 file fe-user (index.css heading-ladder+.label-eyebrow / 6 ui primitives — Button gần SHA-identical fe-admin chỉ khác comment / 6 shell DataTable+RowActions-additive·Layout-brand-left-rail·TopBar·PageHeader·PhaseBadge-ring·EmptyState / LoginPage polish). Rubric mới = guide 13 mục `D:\Dropbox\CONG_VIEC\AI_INFRA\docs\reference\ui-ux-design-guide.md` (density 14px/h32-34/radius-8/thead-sticky/action-luôn-hiện/no-font-bold). BRAND KEPT: #1F7DC1 + Be Vietnam Pro + slate (guide cho plug hue riêng). Chết NGAY TRƯỚC with_server.py screenshot /login → em main recover: build ×2 PASS 0 TS + diff-review key-stability từng file + ship `e959f72`; authed visual qua deploy prod (rig-gotcha #3 standing). LESSON: 2 lần liên tiếp truncate ở CÙNG điểm (sau khi sửa xong, lúc bắt đầu FD2 rig) → lần sau EMIT file-list verdict TRƯỚC khi vào screenshot loop. Tag [s58, fe-user-redesign, guide-aiinfra, keep-brand, truncated-53-proxy].
|
||
- **S55 (2026-06-09) Phase-1 fe-admin redesign — density-first NAMGROUP-ref, KEEP brand [em main proxy — designer truncated gotcha #53 trước build/MEMORY]:** Applied 14 file: index.css (density heading ladder semibold + `.label-eyebrow` 11px uppercase slate-500 + drop font-bold) + 6 ui primitives (Button `text-xs font-semibold rounded-lg` h-7/8/10 + brand focus-ring/70 — variant/size keys STABLE 51 call-sites) + 6 shell (DataTable/Layout/TopBar/PageHeader/PhaseBadge/EmptyState) + DashboardPage (KPI card `rounded-lg border-slate-200` + `bg-brand-50` icon chip h-7w7 + uppercase tracking-wider label + brand accent bar). Brand #1F7DC1 + Be Vietnam Pro KEPT (NAMGROUP density = mượn cấu trúc, brand=ours). `npm run build` 0 TS err. **Visual loop BLOCKED** by authed-rig gotcha (3) above → CHỈ chụp /login (polished, on-brand). em main recover: build ✓ + login-visual ✓ + diff-review (index.css/Button/DashboardPage high-quality, brand-consistent). User chọn commit+deploy → login prod xem authed. Tag [s55, phase1-redesign, density-namgroup, keep-brand, authed-rig-blocked].
|
||
- **S47 (2026-06-02) FD2 RIG VERIFIED ✅** — first real spawn. Ran full FD2 loop end-to-end on fe-user `/login`: read DS (Tailwind v4 CSS-first, corrected stale config-path assumption) → started Vite via `with_server.py` → Playwright screenshot 375+1440 → Read PNGs → FD4 critique → 1-line contrast fix → re-screenshot confirmed → `npm run build` 0 TS error. Closes adap-report `2026-06-02-Agent-frontend-designer-floor` FD2 runtime proof. 2 Vite gotchas captured above. Loop is REAL, not theoretical.
|