Báo cáo chuyển đổi warehouse-service

Kho · warehouse/get-with-paging · api

GET/api/client/page/warehouse/get-with-paging

Vòng
2
Cổng G1–G6
PENDING_SONAR
Bước
sonar-check
Nhánh đích
feat/thongpd/warehouse-create

Báo cáo sai lệch — warehouse/get-with-paging — vòng 2

0. Kết luận nhanh

  • Điều kiện đạt: G1 ✅ G2 ✅ G3 ✅ G4 — G5 ✅ G6 ✅ → CHỜ KIỂM SONAR (máy đạt hết, chờ người kiểm G4)
  • Trạng thái: SẴN SÀNG CHO NGƯỜI XEM — có 1 finding MAJOR UNSURE (key data mất khi danh sách rỗng) cần người chọn cách, xem mục 3d #1
  • Tầng rủi ro: A (R-02 phân quyền; còn lại C chỉ đọc) → người cần đọc: spec + báo cáo + toàn bộ diff
  • Số quy tắc: 11 · PASS 5 · DEVIATION có chủ đích 4 · DEVIATION KHÔNG chủ đích 0 · UNVERIFIED 2
  • Coverage thấp nhất: F-01 97,9% dòng / 91,7% nhánh
  • Finding logic: CRITICAL 0 · MAJOR 0 CONFIRMED còn mở (1 đã sửa) · MINOR 3 · UNSURE 1 (MAJOR)
  • Nghi vấn bug code cũ (mục 3c): 4 (CAO 0) · Quyết định tự chốt cần xác nhận (mục 3d): 11
  • Chạy bằng: /mig-auto (spec do spec-reviewer kiểm, chưa có người duyệt) · Số vòng: 2 verify / lần sửa 1/3

1. Điều kiện đạt

Mã Mục tiêu Kết quả Bằng chứng
G1 mvnw verify ✅ (627 test, 0 lỗi) verify/round-2/build.md
G2 Test khớp test-plan, mọi R-xx có test ✅ (24/24 TC, 11/11 R; TC-02 khác hình thức annotation — mục 3 #3) verify/round-2/oracle.md
G3 Coverage mỗi luồng ✅ verify/round-2/coverage.md
G4 0 issue Sonar CHỜ NGƯỜI sonar-ide.md
G5 0 CRITICAL/MAJOR CONFIRMED ✅ (F-logic-1a đã sửa; F-logic-1b UNSURE không tính) verify/round-2/review-logic.md, verification.md
G6 Không lách cổng ✅ verify/round-2/gates.md

Không chặn nhưng cần người: Integration test CHƯA CHẠY · Golden master CHƯA CHẠY (GM-01)

Coverage theo luồng

Luồng Tên % dòng % nhánh
F-01 Danh sách kho theo trang 97,9% 91,7%

2. Ma trận truy vết

Quy tắc Tầng Code mới Test Golden Kết luận
R-01 C WarehouseController.getWithPaging, WarehousePageFilterRequest TC-01, TC-02, TC-20 — PASS (bind bộ lọc qua record — mục 3 #3; body 400 khác — D-02)
R-02 A WarehouseQueryService.getWarehousePage → CurrentCompanyService TC-03, TC-04 — DEVIATION (có chủ đích, D-01)
R-03 C WarehouseQueryService.keywordPattern, WarehouseRelationalRepository.pageWhere TC-05..TC-08, TC-16, TC-17 GM-01 PASS
R-04 C WarehouseRelationalRepository.pageWhere TC-09, TC-16, TC-17 — PASS
R-05 C WarehouseRelationalRepository.findPage/pageTotal TC-15, TC-16, TC-19, TC-20 GM-01 UNVERIFIED (SQL thật, thứ tự không ORDER BY — D-05, K-13)
R-06 C toListItem/toBoolean, WarehouseListItemResponse (@JsonInclude(ALWAYS)) TC-01, TC-01-EXTRA-1, TC-18 — PASS
R-07 C WarehouseQueryService, InventoryRelationalRepository.countActiveProductsByWarehouses TC-10..TC-12, TC-22 GM-01 UNVERIFIED (SQL thật — K-13)
R-08 C WarehouseController (count, SUCCESS_GET_LIST) TC-01, TC-14 — PASS — trừ data rỗng mất key (F-logic-1b UNSURE, 3d #1)
R-09 C @Transactional không readOnly TC-13 — DEVIATION (có chủ đích, D-06 — giữ đọc DB chính)
R-10 C (không chuyển) TC-24 — DEVIATION (có chủ đích, D-07)
R-11 C bọc PersistenceException ở 2 adapter TC-20, TC-21, TC-23 — PASS (mã giữ, 417→500 — D-03); lỗi ép kiểu khi map dòng chưa bọc (F-logic-3 MINOR)

3. Người cần xem

# Vị trí Vì sao cần người xem
1 Toàn bộ verify/round-2/changes.diff Tầng A (R-02)
2 WarehouseController.getWithPaging + starter-model BaseResponseDTO F-logic-1b UNSURE MAJOR: data: [] → mất key data (3d #1)
3 dto/request/WarehousePageFilterRequest.java, TC-02 Lệch hình thức spec mục 5/TC-02: keyword, status, countProduct bind qua record (Checkstyle tối đa 3 tham số) thay @RequestParam(required=false); hành vi giữ, nhưng sai kiểu thì reason lộ thông điệp convert của Spring (F-logic-4 MINOR)
4 WarehouseController dòng .count(page.total()) F-logic-2 MINOR: cũ ép (int) tổng; chỉ khác khi offset tràn int mà trang có dữ liệu (D-08)
5 WarehouseRelationalRepository.toListItem F-logic-3 MINOR: ép kiểu thủ công ngoài khối bắt lỗi → kiểu cột lạ ra UNCERTAIN_ERROR thay EXCEPTION_ERROR; kiểu cột thật chưa kiểm
6 WarehouseQueryService.getWarehousePage @Transactional không readOnly (D-06) — trái docs/rules/database-performance.md:290
7 Native SQL ở WarehouseRelationalRepository.findPage, InventoryRelationalRepository.countActiveProductsByWarehouses Chỉ test mock (K-13): IN :warehouseIds, setFirstResult không ORDER BY trên MSSQL — chạy GM-01
8 Constructor WarehouseQueryService (thêm 2 dependency), WarehouseController (thêm WarehouseQueryService), hằng PARAM_COM_ID thay chuỗi ở lockCompanyWarehouses/deleteById Chạm code dùng chung của unit khác — không đổi hành vi
9 G4 Người chạy SonarQube for IDE

3b. Phân tích luồng sau chuyển

Chi tiết: verify/round-2/flow-analysis.md

Luồng Tên Số bước KHỚP / KHÁC / CHỈ CÓ Ở CŨ / CHỈ CÓ Ở MỚI Lệch luồng đã duyệt (spec mục 6) Điểm dev cần chú ý
F-01 Danh sách kho theo trang 8 KHỚP / 6 KHÁC (D-01, D-07, D-03 có chủ đích; F-logic-4, F-logic-2, F-logic-1b) / 0 / 0 Không lệch thứ tự; lệch cách bind bộ lọc và serialize data rỗng mapper NON_EMPTY của starter; ép (int) offset; tổng PageImpl; ép kiểu thủ công khi map; IN :warehouseIds; transaction không readOnly

3c. Nghi vấn bug / sai ở code cũ (đã GIỮ nguyên khi chuyển)

B-01 Phân trang không có thứ tự cố định, tham số sort bị bỏ qua

  • Mức nghi ngờ: TRUNG BÌNH — phân trang không ORDER BY là lỗi kinh điển; có thể chưa ai thấy vì công ty ít kho (< 20).
  • Ở đâu: code cũ base:repositories/impl/BaseWarehouseRepositoryImpl.java:51-58, model:util/BaseCommon.java:372-386 → code mới (giữ nguyên) WarehouseRelationalRepository.findPageItems
  • Code cũ đang làm gì: lấy từng trang kho mà không sắp xếp; DB trả theo thứ tự tuỳ ý. Client gửi sort=name,asc cũng không có tác dụng. Cỡ trang tối đa 2000.
  • Ví dụ cụ thể: công ty 45 kho, xem trang 1 (20 kho) rồi trang 2 → có thể có kho xuất hiện ở cả hai trang và có kho không xuất hiện ở trang nào. Lẽ ra trang ổn định theo id hoặc theo sort.
  • Vì sao nghi là sai: Pageable có sort nhưng code bỏ qua; repo đích quy định tối đa 200/trang.
  • Ảnh hưởng nếu đúng là bug: công ty nhiều kho thấy danh sách nhảy, sót/lặp khi chuyển trang.
  • Đã xử lý khi chuyển: GIỮ. Test khoá: TC-16 (WarehouseRelationalRepositoryTest$FindPage#buildsFilteredPagedSql, assert không có ORDER BY), TC-02.
  • Nếu muốn sửa: thêm ORDER BY id (và/hoặc theo sort), giới hạn cỡ trang; đổi TC-16.
  • Liên quan: D-05, R-01, R-05

B-02 Từ khoá toàn dấu cách trả mọi kho trừ kho chưa có tên chuẩn hoá

  • Mức nghi ngờ: THẤP
  • Ở đâu: base:repositories/impl/BaseWarehouseRepositoryImpl.java:34-37 → WarehouseQueryService.keywordPattern
  • Code cũ đang làm gì: keyword="" không lọc; keyword=" " lọc normalized_name like '%%' → bỏ các kho có normalized_name null.
  • Ví dụ cụ thể: 5 kho, 1 kho nhập từ hệ thống cũ có normalized_name = NULL: ô tìm kiếm trống → 5 kho; gõ vài dấu cách → 4 kho. Lẽ ra cả hai đều 5.
  • Vì sao nghi là sai: hai từ khoá "trống" cho kết quả khác nhau.
  • Ảnh hưởng nếu đúng là bug: hiếm, chỉ với kho có normalized_name null.
  • Đã xử lý khi chuyển: GIỮ. Test khoá: TC-07.
  • Nếu muốn sửa: coi từ khoá rỗng sau chuẩn hoá là không lọc; đổi TC-07.
  • Liên quan: D-03, R-03

B-03 Ký tự %, _ trong từ khoá không được escape

  • Mức nghi ngờ: THẤP
  • Ở đâu: base:repositories/impl/BaseWarehouseRepositoryImpl.java:36 → WarehouseQueryService.keywordPattern
  • Code cũ đang làm gì: _ khớp một ký tự bất kỳ, % khớp mọi chuỗi.
  • Ví dụ cụ thể: kho "Kho A1", "Kho AB"; gõ a_ → ra cả 2 kho. Lẽ ra không kho nào. Gõ % → ra mọi kho.
  • Vì sao nghi là sai: người dùng gõ ký tự thường nhận kết quả rộng hơn. (Không phải SQL injection — tham số bind.)
  • Ảnh hưởng nếu đúng là bug: hiếm, chỉ khi gõ ký tự đặc biệt.
  • Đã xử lý khi chuyển: GIỮ. Test khoá: TC-08.
  • Nếu muốn sửa: escape %, _, [; đổi TC-08.
  • Liên quan: D-04, R-03

B-04 Số trang cực lớn làm tràn số → lỗi hệ thống hoặc trả nhầm trang

  • Mức nghi ngờ: THẤP — chỉ với request bất thường.
  • Ở đâu: model:util/BaseCommon.java:384 → WarehouseRelationalRepository.findPageItems
  • Code cũ đang làm gì: vị trí bắt đầu page × size bị ép về số nguyên 32 bit.
  • Ví dụ cụ thể: page=1073742&size=2000 → lỗi hệ thống (cũ 417, mới 500). page=2147484&size=2000 với công ty 800 kho → trả 96 kho từ vị trí 704. Lẽ ra trả rỗng.
  • Vì sao nghi là sai: tràn số.
  • Ảnh hưởng nếu đúng là bug: gần như không gặp khi dùng bình thường.
  • Đã xử lý khi chuyển: GIỮ. Test khoá: TC-20.
  • Nếu muốn sửa: dùng long/chặn số trang; đổi TC-20.
  • Liên quan: D-08, R-01, R-05

3d. Quyết định AI tự chốt và thay đổi tự động (cần người xác nhận)

# Nguồn AI đã làm gì Khác code cũ ở điểm nào (input → cũ / mới) Người cần xác nhận gì
1 F-logic-1b (MAJOR, UNSURE) Không sửa công ty chưa có kho → cũ {…,"data":[],"count":0} / mới {…,"count":0} (không có key data) — do ObjectMapper NON_EMPTY của starter (DataConverterAutoConfiguration.java:51) trên BaseResponseDTO.data. Cùng gốc: warehouse/delete data:null cũng mất key; các API đã chuyển khác cũng vậy Chọn: (a) chấp nhận, ghi D-xx ADR BẮT KHÁC chung; hoặc (b) chỉnh JSON cấp service/starter (MixIn @JsonInclude(ALWAYS) cho data hoặc ObjectMapper riêng) — ảnh hưởng mọi API; chạy thử với công ty không có kho
2 D-01 (LỖI KỸ THUẬT) Kiểm comId của token comId=20 (user công ty 10) → cũ trả kho công ty 20 / mới 400 COMPANY_NOT_OF_CURRENT_USER; comId=0 → cũ 200 rỗng / mới 400 INVALID_COMPANY Đồng ý
3 D-02 (ADR BẮT KHÁC) Body theo starter reason "Lấy dữ liệu thành công" → "SUCCESS_GET_LIST"; thiếu comId → cũ 400 rỗng / mới 400 body starter Frontend đọc mã, không đọc reason
4 D-03 (ADR BẮT KHÁC) Lỗi DB → 500 EXCEPTION_ERROR cũ 417 / mới 500, giữ mã Đồng ý
5 D-06 (MƠ HỒ) @Transactional không readOnly → đọc DB chính readOnly theo quy tắc repo đích sẽ đọc replica (kho vừa tạo có thể chưa thấy) Chọn giữ DB chính (như cũ) hay theo database-performance.md:290; xác nhận cũ đọc DB chính (suy từ cấu hình)
6 D-07 (PHỤ THUỘC NGOÀI) Không kiểm gói dịch vụ công ty hết hạn → cũ 400 / mới 200 Tầng đảm nhận (chung các unit)
7 spec-review Spec qua 1 lần review (0 CRITICAL), R-xx sửa theo MAJOR: R-01 (offset ép int), R-05, R-09 (đọc DB chính), R-11 (mới, giữ EXCEPTION_ERROR) — Đọc kỹ R-01, R-05, R-09, R-11
8 Impl (TC-02, F-logic-4 MINOR) Bộ lọc không bắt buộc bind qua record WarehousePageFilterRequest status=abc → cũ 400 rỗng / mới 400, reason chứa thông điệp convert của Spring Đồng ý cách bind; có cần ẩn thông điệp lỗi convert không
9 F-logic-2 (MINOR) Không sửa offset tràn int mà trang có dữ liệu → cũ count ép int (800) / mới long (4294968096) Có cần giữ ép (int) không (theo D-08)
10 F-logic-3 (MINOR) Không sửa kiểu cột lạ khi map dòng → cũ 417 EXCEPTION_ERROR / mới 500 UNCERTAIN_ERROR Kiểm kiểu cột warehouse trên MSSQL (GM-01)
11 Sự cố quy trình Lỡ chạy git add -N . trong repo đích; đã gỡ bằng git rm --cached cho 11 file mới index về 0 file staged, working tree nguyên Kiểm git status trước khi commit (file mới phải là ??)

4. Finding đã xác nhận

F-logic-1a — MAJOR, parity — CONFIRMED vòng 1 → ĐÃ HẾT vòng 2

Key null trong phần tử data bị mapper NON_EMPTY bỏ. Sửa: @JsonInclude(ALWAYS) trên WarehouseListItemResponse; khoá bằng TC-01-EXTRA-1 (dùng mapper thật của starter). Reviewer vòng 2 xác nhận đúng.

F-logic-1b — MAJOR — UNSURE (mục 3d #1)

F-logic-2, F-logic-3, F-logic-4 — MINOR (mục 3 #3–#5)

5. Finding bị loại

Finding Lý do loại
— —

6. Xử lý của người

Vấn đề Cổng Chỉ thị
G4 — chưa kiểm Sonar G4
F-logic-1b — data rỗng mất key (UNSURE) G5 (không tính)

7. So với vòng trước

Vấn đề Vòng trước Vòng này
F-logic-1a (key null phần tử) MAJOR CONFIRMED ĐÃ HẾT
F-logic-1b (data rỗng) UNSURE CÒN (UNSURE)
F-logic-2, F-logic-3, F-logic-4 MINOR CÒN (không sửa trong vòng lặp)

8. Thay đổi trong repo đích

22 file (verify/round-2/changed-files.md): 15 main Java + 2 i18n + 5 test, đều trong src/main, src/test. Mới: WarehousePageQuery, WarehousePageFilter, WarehouseListItem, WarehousePage, WarehousePageFilterRequest, WarehouseListItemResponse, WarehouseQueryServiceTest. Sửa test của context khác: WarehouseTransferServiceTest (constructor). Không có file ngoài phạm vi.

9. Đề xuất bổ sung kinh nghiệm

Đề xuất Đưa vào đâu
Starter đăng ký ObjectMapper NON_EMPTY: response mới mất key null/rỗng so với monolith (ALWAYS). DTO response mỗi phần tử cần @JsonInclude(ALWAYS); data rỗng/null của BaseResponseDTO mất key ở mọi API — cần quyết định chung legacy-facts (mục 2) + lessons 1b; review-criteria
Test serialize response phải dùng DataConverterAutoConfiguration.buildObjectMapper() của starter, không tự dựng ObjectMapper lessons 1c
Monolith: @Transactional cấp class + provider_disables_autocommit: false → đọc DB chính dù DataSourceAspect đặt READ_ONLY; repo đích readOnly=true đi replica — đọc-sau-ghi khác nhau legacy-facts (mục 4)
Method controller tối đa 3 tham số: API list có nhiều @RequestParam → spec mục 5 phải thiết kế record bộ lọc ngay từ đầu (tránh lệch TC) target-cheatsheet mục 4
Bọc lỗi hạ tầng bằng SystemException.builder().errorCode(...).error(e).build() (PMD PreserveStackTrace) target-cheatsheet mục 3
Không chạy lệnh git ghi index (git add -N) trong repo đích để xem diff; dùng git diff <snapshot tree> + liệt kê ?? lessons 1b / CLAUDE.md

Nguồn của trang này

  • Báo cáo sai lệch migrations/warehouse/get-with-paging/report.md vòng 2 · sha256 9c741e4aa624

v1 dựng 2026-11-06 00:42 · base commit đích a06ccfa6d4