wal: flush 20260812T2138

This commit is contained in:
pqhuy1987
2026-08-12 21:38:52 +07:00
parent 067cd32890
commit 5facab2f48
4 changed files with 81 additions and 8 deletions

View File

@ -38,11 +38,20 @@ remake) · Q2 Select loại GIỮ · Q3 PORT 3 món (cần Mig 73 EndedByLevelFi
nhánh finalize + DTO nở + body nở + panel ×2) · Q4 = XÁC NHẬN W5 hiện trạng (drafter xoá,
approver chỉ trả-lại — đóng vế approver-delete VĨNH VIỄN cho HĐ) · Q5 thay QT-HD-V2-001
bằng 7 HD-* (data-op) + duyệt/history y KHKK (gộp Q1/Q3) + van-xả mirror-theo-KHKK.
[!] WQ3-BE wf-? (mig73+service+DTO+body+guard-mirror+test) ∥ WQ1-FE wf-? (layout KHKK-thuần)
[ ] WQ3b-FE panel 3 món ×2 app (sau 2 wave trên) → commit → WQ5a data-op
[ ] DEPLOY: dọn workspace runner (vá-gốc P0) → push gom → CI → cicd-verify + smoke + báo anh
[x] WQ1-FE DONE 8/8 (ContractListPanel MỚI fe-user-only + MyContractsPage KHKK-thuần;
FLAG panel-3-không-nhân-đôi-nút chuyển WQ3b — sắc) · WQ3-BE #53-skeleton-rỗng NHƯNG
ruột ĐỦ trên đĩa (lead đo 6 mảnh: entity+mig73-3-file+service:527-529+body+DTO+guards
-giữ-nguyên-vì-KHKK-cũng-cho-qua :510-513) · build 0-lỗi · test 693/693 0-regression
[x] WQ5a data-op: seeder QT-HD-V2-001 → IsActive=false từ-lúc-sinh (env mới) + UPDATE Dev
0/0 verified (bền — idempotent-check là existence, né #75). Prod UPDATE cùng câu SQL
@deploy-verify
[!] WQ3-TEST (4 Fact finalize, kỳ vọng 697) ∥ WQ3b-FE (panel 3 món ×2 + tái-vị-trí máy
duyệt về panel-3 mọi host). wf: wf_2989df28-eb6 · artifact sub-wq3-test.md + sub-wq3b-fe.md
[ ] Lead: verify-local vòng 2 (layout mới + finalize) → commit WQ* theo cụm →
DEPLOY: dọn workspace runner → push gom → CI → cicd-verify + prod UPDATE Q5a +
STATUS:476 lật → báo anh kiểm
next: chạy WQ3-BE + WQ1-FE song song.
next: chờ wf_2989df28-eb6 → gate → commit → deploy.
verify:
commits: git log --oneline -8 # 2ae62f3f ed3b39ff 7b291014 09ebd20e 1cc16a2d + wal

View File

@ -1,16 +1,57 @@
# WQ1-FE — remake /my-contracts về layout KHKK-THUẦN (S190 · YC-030 Q1)
Vai: implementer-frontend · run `2026-08-12-S190-soltuon-dieu-chinh-hd`
Ranh: Write/Edit CHỈ {fe-user MyContractsPage.tsx · fe-user components/contracts/ContractListPanel.tsx (MỚI) · sub-md}. KHÔNG fe-admin · KHÔNG ContractWorkflowPanel · KHÔNG commit.
Ranh: Write/Edit CHỈ {fe-user `MyContractsPage.tsx` · fe-user `components/contracts/ContractListPanel.tsx` (MỚI) · sub-md}. KHÔNG fe-admin · KHÔNG `ContractWorkflowPanel` · KHÔNG commit.
(File này = sub-MD của lane; alias trong footer spawn là `sub-implementer-frontend-1.md` — nội dung KHÔNG tách đôi, tất cả ở đây.)
## Việc đã làm
- [lượt 1] Ghi khung rỗng file này (chống #53 — append sau MỖI đơn vị việc).
- **[lượt 1]** Ghi khung rỗng file này (chống #53 — append sau MỖI đơn vị việc).
- **[đọc khuôn]** `fe-user/src/pages/khkk/KhkkListPage.tsx` :1-281 trọn · `fe-user/src/components/khkk/KhkkListPanel.tsx` :1-491 trọn · hiện trạng `fe-user/src/pages/contracts/MyContractsPage.tsx` :1-369 (bản sau W2+W3).
- **[đo đĩa trước khi gõ — 4 phép, đổi cả thiết kế]**
1. `ls fe-admin/src/pages/contracts/` = `ContractCreatePage` · `ContractDetailPage` · `ContractsListPage` · `HardCopiesPage`**KHÔNG có `MyContractsPage`** ⇒ component mới là **fe-user-ONLY có chủ đích**, KHÔNG có cặp SHA để mirror (khai ngay ở header file mới :6-11).
2. 🔴 `fe-user/src/components/contracts/ContractDetailContent.tsx:331-335` **ĐÃ render `<ContractWorkflowPanel contract={c} />`** trong nhánh `isV2` ⇒ nếu panel-3 render thêm thì **một HĐ có HAI bộ nút Duyệt/Trả lại** — đúng thứ chính khối W6 cấm ở `ContractDetailContent.tsx:140-142` ("để cả hai thì cùng một HĐ V2 có 2 đường bấm duyệt"). ⇒ **lệch spec có chủ đích**, xem §DEFERRED.
3. `usePipelineStages.ts:83` + index `enabled: canPe` ⇒ cây GĐ3 cũng chết khi thiếu quyền Duyệt NCC ⇒ **bê nguyên mitigation M-1 của KHKK** (`!canPe` ép chế-độ phẳng), nếu không thì gộp 2 cột thành 1 sẽ làm người chỉ-có-quyền-HĐ **mất trắng danh sách** (mặt còn lại gotcha #82).
4. `git show 502f4d2e:…MyContractsPage.tsx` (bản TRƯỚC-W2) ⇒ panel-3 khi đó = `WorkflowHistoryPanel` trong `aside … w 360px p-4`**bề ngang 360px đã có tiền lệ chạy thật** (bài học #15: đo bề ngang trước khi port khuôn).
- **[thi công 1]** TẠO `fe-user/src/components/contracts/ContractListPanel.tsx` (346 dòng) — mirror-ADAPT `KhkkListPanel`:
- filter-block trên cùng theo đúng thứ tự spec: `Select` **loại HĐ** (Q2 — giữ từ W2) → ô **Tìm**`Select` **trạng thái** (khuôn KHKK, nguồn nhãn `ContractPhaseLabel` 12 mục).
- `flatMode = !canPe || term.length > 0 || phase !== null || pendingMe || deletedView` (`:139`). CÂY = mặc định: `PipelineTreePanel currentStage={3} hideHeader hideSearch bodyMaxHClass="lg:max-h-none"` + `stage2Options={{ onOpenContract, stage3TypeFilter }}`.
- Query `['my-contracts', type, phase, deletedView, term, pendingMe]` **dời nguyên từ host xuống panel** + `enabled: flatMode` (khuôn `KhkkListPanel.tsx:260` — chế-độ cây KHÔNG gọi endpoint nữa). Giữ nguyên 3 nhánh endpoint của W3/W7: `deleted``pendingMe` (`/contracts/inbox`, 0 tham số, lọc loại ở client, nợ `[carry:w7b-inbox-param]`) → thường.
- Card `ContractRowCard` = **markup cũ dời chỗ, không vẽ lại** (mã · tên · NCC · chip phase · giá + `SlaTimer`).
- **THÊM 3 thứ KHÔNG có ở bản W2** (đều là chống-câm, khai ở đây để reviewer không tưởng scope creep): (a) nhánh `list.isError` + nút "Thử lại" — trước đó lỗi mạng đọc thành "Không có HĐ"; (b) chân cột `x / total HĐ` + cảnh báo cắt `PAGE_SIZE=100` (trang chưa có UI phân trang); (c) dòng chữ hiện "cây dựng từ phiếu Duyệt NCC — HĐ ngoài gói không nằm trên cây…" chỉ hiện ở chế-độ cây.
- **[thi công 2]** VIẾT LẠI `MyContractsPage.tsx` (369 → 215 dòng): grid GIỮ `[400px_1fr_360px]`; panel-1 = `ContractListPanel`; panel-2 = `ContractDetailContent` (bỏ `WorkflowHistoryPanel` khỏi đây); panel-3 = **khuôn KHKK QĐ-2** hộp `border-dashed` + icon `X` khi chưa chọn ⟂ `WorkflowHistoryPanel` khi đã chọn. **BỎ cột danh-sách thường-trực** (nay là chế-độ phẳng của panel-1). BỎ badge `{rows.length}` ở header (không còn nguồn: chế-độ cây không có "số dòng" — số đếm xuống chân panel-1).
- **[thi công 3]** Lớp override lọc: 1 state `{nav, type, phase}` **đóng dấu leaf** (`navKey = type|phase|deleted|pendingMe`) — đổi leaf ⇒ dấu lệch ⇒ override tự rơi. **KHÔNG `useEffect`** (bài W2: ăn `react-hooks/set-state-in-effect`, 47→48) và **KHÔNG set-state-trong-render** (khuôn KHKK `KhkkListPage.tsx:83-88` dùng cách đó; ở đây dẫn-xuất thuần nên tránh luôn rủi ro lint). 3 trạng thái `undefined`/`null`/số giữ nguyên nghĩa KHKK.
- **[thi công 4]** `Select` loại HĐ nay lọc **CẢ cây LẪN danh sách** (W2: chỉ cây). Lý do khai tại `ContractListPanel.tsx` khối `queryFn`: gộp 2 cột thành 1 mà `Select` chỉ lọc cây thì ở chế-độ phẳng nó là **nút chết**. Kéo theo: `typeLabel` ở header + `?type=` của nút "Tạo HĐ mới" đọc loại **ĐÃ GIẢI** (khuôn `KhkkListPage.tsx:151-153` đọc `group` đã giải) — chọn "Tất cả loại HĐ" mà tiêu đề còn treo tên 1 loại là tiêu đề nói dối.
- **[GIỮ nguyên]** `?id=` chọn tại chỗ · deep-link `/contracts/{id}` khi `<lg` (`window.matchMedia('(min-width: 1024px)')`) · chặn mở khi `deleted=1` (2 lớp: `selectContract` return sớm + card `disabled`) · `?q=` ghi URL `{replace:true}` · nhãn chế-độ ở header (Đã xóa / Đã phát hành / Đang duyệt).
## Ô acceptance
(chưa đo)
| # | Ô | Lệnh | Số đo | Verdict |
|---|---|---|---|---|
| A1 | `ContractListPanel` trong page ≥1 | `grep -c` | **6** | PASS |
| A2 | `border-dashed` trong page ≥1 (panel-3 dashed) | `grep -c` | **1** | PASS |
| A3 | `{!selectedId && <PipelineTreePanel` = 0 | `grep -cF` | **0** | PASS |
| A3-ctrl | control-DƯƠNG cùng regex trên `081557b4` (bản từng có khối đó) | `git show \| grep -cF` | **1** | phép đo CÓ RĂNG |
| A3b | `<PipelineTreePanel` element trong page = 0 | `grep -c` | **0** (HEAD bản W3 = **1**) | PASS + control-dương |
| A4 | `flatMode\|isFlat` trong panel ≥2 | `grep -cE` | **9** | PASS |
| A5 | eslint fe-user KHÔNG TĂNG (baseline 47) | `npx eslint .` | **47 problems (41 error/6 warn)** — 2 file mới: **0** | PASS |
| A6 | `npm run build` fe-user EXIT 0 | `npm run build` | **BUILD_EXIT=0**, built in 16.65s | PASS |
| A7 | `tsc -b` EXIT 0 | `npx tsc -b` | **TSC_EXIT=0** | PASS |
**8/8 ô máy PASS** (A3-ctrl tính là chứng-cứ của A3, không tính ô riêng ⇒ 8 dòng đo, 0 FAIL).
Phụ — chống **bẫy tự-trích-dẫn** (bài S188): `grep -c 'ContractWorkflowPanel' MyContractsPage` = **1** hit, nhưng bỏ dòng `//` còn **0** ⇒ hit duy nhất là **văn xuôi trong comment FLAG**, KHÔNG phải render. Tương tự `PipelineTreePanel` còn **1** hit ở `:197` — nằm trong `{/* … */}` (khối comment JSX), câu chữ là "KHÔNG nhét `PipelineTreePanel` vào đây".
Warning build = **PRE-EXISTING** (chunk >500 kB + `INEFFECTIVE_DYNAMIC_IMPORT src/lib/realtime.ts`), đúng như 3 đợt trước — không đổ lỗi cho đợt này.
Pattern 16-bis 4-place: **N/A có bằng chứng** — không thêm route/menu-key nào. `fe-user/src/App.tsx:66` đã có `<Route path="/my-contracts" …>`; `Layout.tsx:90,166,174,179` đã trỏ 4 leaf về đúng URL này. Đợt này chỉ đổi RUỘT của trang.
Diện chạm: `git status --short fe-user fe-admin` = **đúng 2 dòng** (`M MyContractsPage.tsx`, `?? ContractListPanel.tsx`), **fe-admin 0 dòng**.
## DEFERRED/DỪNG
(chưa có)
1. 🔴 **FLAG WQ1→WQ3b — panel-3 CỐ Ý KHÔNG có `ContractWorkflowPanel` (lệch spec BƯỚC 2(2), có bằng chứng).** Spec bảo panel-3 = `ContractWorkflowPanel + WorkflowHistoryPanel`, nhưng `ContractDetailContent.tsx:331-335` **đã** render `ContractWorkflowPanel` (nhánh `isV2`) và `ContractDetailContent` chính là panel-2 ⇒ làm đúng chữ spec = **2 bộ nút Duyệt/Trả lại cho cùng 1 HĐ**. Gỡ khối `isV2` khỏi `ContractDetailContent` là cách đúng, nhưng file đó (a) **ngoài ranh WQ1**, (b) là **cặp mirror ×2 app**, (c) còn nuôi cả `ContractDetailPage` fullpage. ⇒ Để WQ3b/lead quyết. Panel-3 hiện = dashed ⟂ `WorkflowHistoryPanel` (sơ đồ quy trình + duyệt phòng ban + lịch sử) = đúng hình KHKK QĐ-2 **trừ 2 nút bấm**.
2. **HÀNH VI = DEFERRED-TO-LOCAL-VERIFY** (lead đo trên máy): (a) cây GĐ3 mở ra đúng ở `/my-contracts` trần; (b) gõ tìm / chọn trạng thái ⇒ nhảy sang danh sách phẳng và ngược lại; (c) 4 leaf menu (List/Pending/Approved/Deleted) vào đúng chế-độ; (d) `<lg` bấm row vẫn ra fullpage; (e) panel-3 dashed → có nội dung khi chọn HĐ.
3. **Chưa đụng phân trang.** Chế-độ phẳng vẫn `pageSize: 100` trang 1 như W2/W7 (KHÔNG có UI phân trang). Nay ít nhất **nói ra** chỗ bị cắt (`x / total` + dòng amber) thay vì cắt câm. Muốn phân trang thật = việc đợt sau (KHKK có sẵn khuôn `KhkkListPanel.tsx:457-488`).
4. **Nợ cũ giữ nguyên `[carry:w7b-inbox-param]`:** `GET /contracts/inbox` là record 0 tham số + `Take(100)` cứng ⇒ chế-độ "Đang duyệt" khoá ô tìm và ẩn `Select` trạng thái, lọc loại chạy client. Đã nói bằng **chữ hiện** (không dùng `title` trên control `disabled` — bài S182).
5. **Dòng chữ "HĐ ngoài gói"** (`ContractListPanel` cuối khối filter) là **phán đoán của lane**, không có trong spec: nó là đường DUY NHẤT lộ ra cho HĐ tạo trực tiếp sau khi cột danh-sách bị gộp. Anh từng bảo bỏ mấy dòng giải-thích cơ-chế ở KHKK (S175) ⇒ **nếu anh không thích, xoá 1 khối `{!flatMode && (…)}` là xong**, không kéo theo gì.

View File

@ -0,0 +1,16 @@
# WQ3-TEST — test nhánh FINALIZE Hợp đồng (YC-030 Q3)
Agent: test-specialist · Run: 2026-08-12-S190-soltuon-dieu-chinh-hd
Ranh: Write CHỈ {ContractApproveFinalizeTests.cs, sub-wq3-test.md}. KHÔNG commit. KHÔNG chạm production code.
## Ca đã viết
(CHƯA VIẾT — đang đọc BƯỚC 1)
## Kết quả chạy
(CHƯA ĐO)
## Ghi chú
(đang đọc)

View File

@ -0,0 +1,7 @@
# WQ3b-FE — port 3 mon KHKK vao panel duyet HD + tai-vi-tri may duyet ve panel-3 (S190 · YC-030)
## Việc đã làm
## Ô acceptance
## DEFERRED/DỪNG