Files
solution-erp/.claude/workflows/runs/2026-08-01-S169-bookend-open/sleep-drafts/implementer-backend--2026-05-q2.gist.draft.md
2026-08-03 10:14:49 +07:00

12 KiB
Raw Blame History

implementer-backend/2026-05-q2 — gist

distill-gen: 1 source-verbatim: .claude/agent-memory/implementer-backend/archive/2026-05-q2.md (5 entry → 5 cụm) pointer-style: substring

TỔNG-HỢP (3-5 ý)

  1. Mirror phải chứng bằng máy, không bằng mắt: SHA256 sau khi ghi (AG 21001E90…; Plan CA 4 hash) hoặc git diff --stat byte-similar; Pattern 5 (mirror 2 app §3.9) tự đếm tích-luỹ 7th → 8th → 9th — kinh-nghiệm biến thành con-số kiểm được.
  2. Gộp N nhánh log về MỘT đường chung (Plan AB cdfd542: gỡ return sớm nhánh Drafter → 1 Changelog.Add() duy nhất cuối phủ cả 4 mode); FE lọc bằng substring của summary (động-từ tiếng Việt) thay enum cứng ⇒ thêm luật lọc mới không cần migrate BE.
  3. Pattern 19 — thiếu thư-viện thì dùng thẻ HTML gốc: <details>/<summary> + Tailwind named-group + localStorage (fe-user không có Accordion); anti-pattern nested group không đặt tên ⇒ con kế-thừa trạng-thái cha, cả hai chevron xoay cùng lúc.
  4. VA-CHẠM số-hiệu Pattern 16 (2 nghĩa khác nhau trong cùng file — CẤM gộp khi nén) + bẫy công-cụ: PowerShell $_ trong ForEach-Object bị Bash tool nuốt khi escape ⇒ đổi sang Get-FileHash dạng liệt-kê — chính cách gọi shell làm hỏng phép kiểm, không phải lệnh sai.

Entries

⚠️ VA-CHẠM Pattern 16 (fidelity — giữ nguyên từ curator, lead định-đoạt): trong verbatim, nhãn "Pattern 16 NEW" được gán cho HAI thứ khác nhau: (S25 wrap) "Preventive systemic batch fix khi audit phát hiện 9 sites cùng bug pattern" ⟂ (S27 Plan CA) "byte-identical mirror admin → user khi parity confirmed". Verbatim q4 tự khai chỗ mờ: "Pattern 16 baseline implied trong recent activity S27 chưa numbered explicit". ⇒ CẤM gộp 2 mục này thành một chỉ vì trùng số.

[cao] G1 — Plan AB Chunk A: gộp 4 nhánh về một chỗ ghi log

  • VIỆC: sửa 2 lỗi UAT về nhật-ký duyệt (cdfd542, 3 file, +146/-95).
  • KẾT-LUẬN: BE viết lại ApplyReturnModeAsync (:215-378): bỏ return sớm của nhánh Drafter (~:282-287) → chuyển thành if/else một đường chung, để một Changelog.Add() duy nhất ở cuối phủ cả 4 mode (Summary=$"Trả lại ({modeName}): {summary}", modeName switch 4 giá-trị tiếng Việt); actorName lấy qua userManager.FindByIdAsync theo đúng khuôn LogTransition ~:660-667; không gọi SaveChangesAsync mới vì caller TransitionAsync:100 đã lưu. FE 2 app nới bộ lọc: theo summary chứa "Trả lại" (Workflow) và entityType === PE_ENTITY_HEADER(=1) + chứa "ngân sách". Test bỏ qua theo chế-độ UAT (giữ mốc 111).
  • BÀI-HỌC: khi N nhánh cùng phải ghi một loại log, gỡ return sớm để có đường chung rồi ghi một lần — thay vì rải N lời gọi. Và lọc ở FE bằng chuỗi con của summary (động-từ tiếng Việt) thay vì enum cứng: FE thêm luật lọc mới không cần migrate BE.
  • BẤT-NGỜ: cùng một đoạn được tả 2 lần trong cùng file với số dòng lệch nhau (282-287 ở entry dày vs 280-287 ở entry wrap) ⇒ khi hợp-nhất phải chọn bản dày, đừng trộn số. → substring:"cdfd542"

[cao] G2 — Plan AG: cây 2 tầng bằng HTML thuần (Pattern 19)

  • VIỆC: bro phản-hồi danh-sách PE phẳng là "đám rừng" → dựng cây Dự-án ▸ Gói-thầu kiểu thư-mục Outlook (0bf6c7e, 2 file, +346/-116).
  • KẾT-LUẬN: gom bằng useMemo 2 tầng (ProjectGroup / GoiThauGroup, khoá chuẩn-hoá trim+toLowerCase, hiển-thị bản gốc đầu tiên), có nhánh dự-phòng "(Dự án đã xoá)" / "(Chưa phân loại)", sắp theo locale vi, lọc trước khi gom để trạng-thái rỗng đúng. UI dùng <details>/<summary> thuần trình-duyệt (fe-user không có Accordion của shadcn) + Tailwind named group group/proj · group/gt + [&::-webkit-details-marker]:hidden. Ghi nhớ trạng-thái mở bằng localStorage (pe_list_expanded_groups, khoá ${projectId}::${normalizedGoiThau}, mặc-định đóng hết) có try/catch phòng chế-độ ẩn-danh. 2 app giống nhau tới SHA256 (21001E90…).
  • BÀI-HỌC: thiếu thư-viện thì dùng thẻ HTML gốc: <details> cho sẵn trạng-thái đóng/mở, bàn-phím Space/Enter, 0 dòng JS quản trạng-thái từng nút. Đổi thước đếm cũng phải đổi đồng-bộ (rows.lengthprojectGroups.length), nếu không trạng-thái rỗng sẽ nói dối.
  • BẤT-NGỜ: anti-pattern được ghi rõ: nếu hai group lồng nhau trùng tên group (không đặt tên) thì con kế thừa trạng-thái cha ⇒ cả hai xoay chevron cùng lúc — một lỗi UI chỉ lộ khi lồng, và named-group là cách chữa. → substring:"pe_list_expanded_groups"

[cao] G3 — Plan CA Chunk B: mirror nguyên-si + bẫy PowerShell

  • VIỆC: dời 4 trang danh-mục từ fe-admin sang fe-user (06a441c, 6 file, +962 LOC).
  • KẾT-LUẬN: vì Investigator đã xác-nhận 2 app ngang bằng (DataTable/PageHeader/PermissionGuard/usePermission/6 shadcn/types), nên chép nguyên file không sửa, rồi verify SHA256 cả 4 (C1760788…/BDF0529E…/68213D62…/6F482614…) ⇒ an-toàn vì mã bên admin đã qua UAT. Đúc pattern_master_page_mirror.md.
  • BÀI-HỌC: "chép y nguyên" chỉ hợp-lệ khi đã chứng ngang-bằng trước; và bằng-chứng phải là hash sau khi ghi, không phải cảm-giác đã-copy-đúng.
  • BẤT-NGỜ: bẫy công-cụ: biến $_ của PowerShell trong khối ForEach-Object bị Bash tool nuốt khi escape ⇒ phải đổi sang dạng liệt-kê Get-FileHash file1, file2, … | Format-Table thay vì lặp qua pipeline. Tức chính cách gọi shell làm hỏng phép kiểm, không phải lệnh sai. → substring:"06a441c"

[vừa] G4 — Plan B Chunk D: dropdown V2 cho ContractCreatePage

  • VIỆC: mirror ô chọn quy-trình V2 từ PE sang HĐ (62b50d1, 2 file, +44 LOC mỗi app).
  • KẾT-LUẬN: dựa nguyên bản PeWorkspaceCreateView.tsx (:80-89 useQuery + :152-172 UI Select), đổi duy nhất trường phân-biệt ApplicableType=3; kiểm tiền-đề BE trước khi wire: CreateContractCommand (ContractFeatures.cs:17-36) đã có Guid? ApprovalWorkflowId = null kèm marker của em-main ⇒ không lệch DTO. Áp Pattern 16-bis 4 chỗ: trang ×2 DONE, còn Routes / menuKeys / Layout staticMap đều N/A có lý-do.
  • BÀI-HỌC: mirror xuyên module thì liệt-kê đủ 4 chỗ rồi ghi N/A kèm lý-do, đừng im lặng bỏ qua — "N/A" có lý-do mới chứng-minh là đã xét.
  • BẤT-NGỜ: vai kiểm tiền-đề phía BE trước khi sửa FE (đọc record của commit em-main làm trước) — nhờ vậy không đẻ ra lỗi lệch hợp-đồng dữ-liệu; và tự khai phần cố-ý không làm (chỉ ContractHeaderForm, không đụng ContractEditForm). → substring:"62b50d1"

[cao] G5 — META: mirror phải chứng bằng hash

  • VIỆC: trục lặp ở 3/5 entry.
  • KẾT-LUẬN: Pattern 5 (mirror 2 app §3.9) được đếm tích-luỹ lần 7 → 8 → 9; mỗi lần đều kèm bằng-chứng máy: SHA256 khớp (AG, CA) hoặc git diff --stat byte-similar (Chunk D). Verbatim còn đề-xuất biến thành công-cụ: "recommend tooling git diff fe-admin/X fe-user/X after every multi-file edit batch".
  • BÀI-HỌC: với công-việc nhân-bản, đối-chứng máy rẻ hơn review mắt và phát-hiện được thứ mắt không thấy (khác 1 ký-tự).
  • BẤT-NGỜ: vai tự đếm số lần áp-dụng một pattern (7/8/9) — biến "kinh-nghiệm" thành con-số kiểm được, thay vì nói "đã dùng nhiều lần". → substring:"git diff fe-admin"

Phụ-lục token (coverage)

  • Pattern#: 4 feedback_service_hook_vs_endpoint (log trong service hook, KHÔNG endpoint /return-changelog rời) · 5 mirror 2 app §3.9 (7th/8th/9th cumulative) · 16 (VA-CHẠM — 2 nghĩa, xem cảnh-báo trên) · 16-bis kiểm 4 chỗ cross-app · 17 FE merge synthetic row · 18 FE userMap fallback từ dữ-liệu nhúng · 19 <details>+named group+localStorage · 12-bis cookie-cutter xuyên module · Pattern 7 (per-NV opt-in, nhắc lại)
  • criteria#: #4 (tight coupling BE+FE ⇒ vai sẽ REFUSE Plan AC trở đi)
  • surprise: "Gotcha S27: PowerShell $_ variable in ForEach-Object block bị Bash tool shell-escape eaten" · "fe-user no shadcn Accordion → native browser disclosure widget free" · "Anti-pattern: nested same-name group would inherit parent state → both rotate sync" · "Mirror 2 app §3.9 IDENTICAL post-edit (SHA256 verify match 21001E90...)" · "stash em main WIP ... race condition trick" (nhắc chéo) · "KHÔNG ops git push (em main verify Reviewer rồi mới push)" (lặp 3 entry) · "FE filter qua substring summary keyword chứ KHÔNG enum field strict" · "recommend tooling git diff fe-admin/X fe-user/X after every multi-file edit batch" · số dòng lệch 282-287 vs 280-287 cho cùng đoạn
  • guard: try/catch quanh localStorage (quota / ẩn-danh) · lọc pendingMe TRƯỚC khi gom nhóm · projectGroups.length === 0 thay rows.length === 0 · SHA256 sau khi ghi (4 file) · git diff --stat byte-similar · kiểm tiền-đề BE (Guid? ApprovalWorkflowId = null) trước khi wire FE · [&::-webkit-details-marker]:hidden · named group group/projgroup mặc-định · không gọi SaveChangesAsync mới (caller đã lưu)
  • root-cause: return sớm ở nhánh Drafter ⇒ không có đường chung ⇒ phải rải nhiều lời-gọi log ⇒ gom về if/else + 1 Changelog.Add() · fe-user thiếu Accordion ⇒ chuyển sang <details> gốc · group không đặt tên khi lồng ⇒ con kế-thừa trạng-thái cha · Bash tool escape nuốt $_ForEach-Object gãy
  • file:line / định-danh: PurchaseEvaluationWorkflowService.cs ApplyReturnModeAsync :215-378, Drafter early-return :282-287 (wrap ghi :280-287), userManager.FindByIdAsync mirror :660-667, caller TransitionAsync :100 · PeDetailTabs.tsx ×2 (filter + comment 3-nguồn) · PE_ENTITY_HEADER = 1 · Summary=$"Trả lại ({modeName}): {summary}" ("Người soạn thảo"/"1 Cấp"/"1 Bước"/"Người chỉ định") · ProjectGroup{projectId, projectName, goiThauList[], totalCount} · GoiThauGroup{displayName, normalizedKey, items[]} · pe_list_expanded_groups · __no_project__ · ${projectId}::${normalizedGoiThau} · group/proj · group/gt · group-open/proj:rotate-90 · PeWorkspaceCreateView.tsx :80-89 + :152-172 · ContractCreatePage.tsx ×2 · CreateContractCommand @ ContractFeatures.cs :17-36 (Guid? ApprovalWorkflowId = null, marker [Plan B S29 2026-05-22 Chunk E1]) · ApplicableType=3 · Mig 25 IsUserSelectable · pattern_master_page_mirror.md · feedback_uat_skip_verify
  • sha / số-đo: cdfd542 (3 file +146/-95; BE +83/-49; FE +14/-6 mỗi app) · 0bf6c7e (2 file +346/-116 = +115 mỗi app) · 06a441c (6 file, +962) · 62b50d1 (2 file, +44 ×2 = +88) · SHA256 21001E90… · C1760788… / BDF0529E… / 68213D62… / 6F482614… · build: BE 20.27s · fe-user 1907 module 16.62s / 16.05s / 14.14s / 8.84s · fe-admin 1926 module 6.98s / 6.86s / 16.07s · bundle fe-user 1291.33 KB (gzip 337.00) / 1.32MB (gzip 343KB) · fe-admin 1402.68 KB (gzip 357.51) / 1.40MB (gzip 358KB) · test mốc 111 (bỏ qua theo UAT) · token ~10k-16k · warn nền: CSS @import + INEFFECTIVE_DYNAMIC_IMPORT realtime.ts (lặp 3 entry) · tag [pattern, phase-9, frontend]