Báo cáo sai lệch — inventory/get-detail-product — vòng 1
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
- Tầng rủi ro: C (chỉ đọc) → người cần đọc: spec + báo cáo
- Số quy tắc: 11 · PASS 4 (R-03, R-04, R-05, R-07) · DEVIATION có chủ đích 5 (R-01, R-02, R-08, R-10, R-11) · DEVIATION KHÔNG chủ đích 0 · UNVERIFIED 2 (R-06 thứ tự lô trong kho, R-09 DB đọc của code cũ) — xem mục 2
- Coverage thấp nhất: F-01 100% dòng (38/38) / nhánh N/A (0 nhánh mới)
- Finding logic: CRITICAL 0 · MAJOR 0 · MINOR 1 · UNSURE 0
- Nghi vấn bug code cũ (mục 3c): 1 (CAO 0) · Quyết định tự chốt cần xác nhận (mục 3d): 7
- Chạy bằng:
/mig-autolượt20261105-1351(spec dospec-reviewerkiểm, chưa có người duyệt) · Số vòng: 1 verify / lần sửa 0/3
1. Điều kiện đạt
| Mã | Mục tiêu | Kết quả | Bằng chứng |
|---|---|---|---|
| G1 | Kiến trúc ADR (mvnw verify: build, test, ArchUnit, Checkstyle/PMD/SpotBugs) |
✅ | verify/round-1/build.md (599 test, exit 0) |
| G2 | Test khớp test-plan, mọi R-xx có test | ✅ | verify/round-1/oracle.md (22/22 TC) |
| G3 | Coverage mỗi luồng (dòng ≥ 80%, nhánh ≥ 70%) | ✅ | verify/round-1/coverage.md |
| G4 | 0 issue Sonar (người kiểm bằng SonarQube for IDE) | CHỜ NGƯỜI | sonar-ide.md |
| G5 | 0 finding logic CRITICAL/MAJOR đã xác nhận | ✅ | verify/round-1/review-logic.md (không cần xác minh — không có CRITICAL/MAJOR) |
| G6 | Không lách cổng, không ghi ngoài phạm vi | ✅ | verify/round-1/gates.md; 16 file đều có trong impl-notes.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, chưa cấu hình)
Coverage theo luồng
| Luồng | Tên | % dòng | % nhánh |
|---|---|---|---|
| F-01 | Tồn chi tiết một ĐVT theo kho và lô | 100.0% (38/38) | N/A (0/0) |
2. Ma trận truy vết
| Quy tắc | Tầng | Code mới | Test | Golden | Kết luận |
|---|---|---|---|---|---|
| R-01 | C | InventoryController.java:42-53 |
TC-01, 02, 03 | — | DEVIATION (có chủ đích, D-02: body 400 theo starter) |
| R-02 | C | InventoryQueryService.java:42-46 |
TC-04..07 | — | DEVIATION (có chủ đích, D-01) |
| R-03 | C | ProductStockDetailJdbcRepository.java:30-47 |
TC-08, 09, 10 | GM-01 | PASS (H2; MSSQL thật UNVERIFIED — K-13) |
| R-04 | C | ProductStockDetailJdbcRepository.java:39,49-60 |
TC-11, 12, 13 | GM-01 | PASS |
| R-05 | C | InventoryWebMapper.java:25-29 |
TC-14 | — | PASS |
| R-06 | C | ProductStockDetailJdbcRepository.java:46 |
TC-15 | GM-01 | UNVERIFIED (thứ tự lô trong cùng kho do DB — D-03) |
| R-07 | C | ProductStockDetailResponse.java, InventoryWebMapper.java |
TC-16, 17, 18 | — | PASS (tên key pid/ppuidAndWarehouseId suy từ Jackson — so response thật ở GM-01) |
| R-08 | C | InventoryController.java:51-52 |
TC-19, 20 | — | DEVIATION (có chủ đích, D-02, D-07) |
| R-09 | C | InventoryQueryService.java:42 |
TC-21 | — | UNVERIFIED (DB đọc của code cũ suy từ cấu hình — D-04) |
| R-10 | C | — | — | — | DEVIATION (có chủ đích, D-05 — không chuyển kiểm gói) |
| R-11 | C | InventoryRelationalRepository.java:51-57 |
TC-22 | — | DEVIATION (có chủ đích, D-06: 417 → 500, giữ mã) |
3. Người cần xem
| # | Vị trí | Vì sao cần người xem |
|---|---|---|
| 1 | ProductStockDetailJdbcRepository.java:30-47 |
SQL native chỉ chạy trên H2 (chế độ MSSQL); chạy GM-01 trên MSSQL thật để chốt R-03, R-04, R-06 (K-13) |
| 2 | ProductStockDetailJdbcRepository.java (F-logic-1, MINOR) |
Lệch spec mục 5: tách lớp JDBC riêng thay vì thêm vào InventoryJpaRepositoryCustomImpl (thêm vào lớp cũ làm PMD CyclomaticComplexity đỏ). Không đổi hành vi |
| 3 | InventoryQueryService.java |
Lớp dùng chung cho context khác nay phụ thuộc CurrentCompanyService; đã sửa 1 dòng WarehouseTransferServiceTest.java:135. Lưu ý gộp nhánh: repo chính đang sửa dở chính file này (unit warehouse/get-with-paging) |
| 4 | R-07 | Tên key JSON pid, ppuidAndWarehouseId suy từ quy tắc đặt tên của Jackson 2.13 — UNVERIFIED tới khi so response thật |
| 5 | R-09 (D-04) | Code cũ đọc DB chính hay replica chỉ suy từ cấu hình — UNVERIFIED |
| 6 | G4 | Sonar chưa kiểm |
3b. Phân tích luồng sau chuyển
Chi tiết: verify/round-1/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 | Tồn chi tiết một ĐVT theo kho và lô | 6 / 5 (đều có chủ đích: D-01, D-02, D-05, D-06, D-07) / 0 / 0 | Thêm tầng ProductStockDetailJdbcRepository (F-logic-1) |
SQL native + thứ tự tham số (comId 2 lần) chưa chạy MSSQL; is_primary đọc Boolean phụ thuộc kiểu BIT; @JsonInclude(ALWAYS) bắt buộc giữ; list rỗng mất key data |
3c. Nghi vấn bug / sai ở code cũ (đã GIỮ nguyên khi chuyển)
B-01 Các lô trong cùng một kho trả về theo thứ tự ngẫu nhiên
- Mức nghi ngờ: THẤP — có thể màn hình tự sắp lại; chỉ thấy
ORDER BYkhông đủ, chưa thấy nơi dùng thứ tự này để quyết định nghiệp vụ. - Ở đâu: code cũ
easyposbase:src/main/java/sds/ep/baseservice/repositories/impl/BaseInventoryRepositoryImpl.java:82→ code mới (giữ nguyên)src/main/java/com/softdreams/easypos/warehouse/infrastructure/relational/inventory/jpa/ProductStockDetailJdbcRepository.java:46 - Code cũ đang làm gì: sắp kết quả theo sản phẩm, kho, rồi "ĐVT chính trước". Vì API chỉ hỏi một ĐVT nên chỉ còn sắp theo kho; các lô trong cùng kho không có tiêu chí sắp.
- Ví dụ cụ thể: kho 6 có lô 301 (HSD 12/2026) và lô 302 (HSD 03/2027) → hệ thống cũ (và mới) có thể trả 301, 302 ở lần gọi này và 302, 301 ở lần gọi khác, tuỳ SQL Server. Nếu muốn ổn định thì lẽ ra phải sắp thêm theo lô hoặc HSD.
- Vì sao nghi là sai:
is_primary descvô nghĩa khi chỉ có một ĐVT; API khác trong cùng code (createBatchOnHandMap) có sắp lô theo HSD, API này thì không. - Ảnh hưởng nếu đúng là bug: danh sách lô trên màn hình nhảy thứ tự giữa các lần mở; người chọn "lô đầu tiên" có thể chọn lô khác nhau.
- Đã xử lý khi chuyển: GIỮ nguyên hành vi cũ. Test khoá hành vi này:
TC-15(ProductStockDetailJdbcRepositoryTest#orderByAsLegacy) — đổi hành vi thì test này phải đổi theo. - Nếu muốn sửa: thêm
bd.batch_id(hoặc HSD qua bảngbatches) vàoORDER BYởProductStockDetailJdbcRepository.java:46, sửa TC-15; monolith còn chạy song song sẽ trả thứ tự khác service mới. - Liên quan: D-03, R-06
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 | D-07 (ADR BẮT KHÁC) | Giữ BaseResponseDTO + mapper starter |
?comId=10&ppuId=999999 → cũ "data":[] / mới không có key data |
Chốt chung với warehouse/get-with-paging F-logic-1: chấp nhận hay đổi cấu hình JSON cấp service |
| 2 | D-01 (LỖI KỸ THUẬT) | Thêm kiểm công ty của token | comId=20 (user công ty 10) → cũ trả tồn công ty 20 / mới 400 COMPANY_NOT_OF_CURRENT_USER; comId=0 → cũ data=[] / mới 400 INVALID_COMPANY; token không có companyId → cũ trả tồn / mới TOKEN_INVALID_OR_EXPIRED |
Đồng ý chặn |
| 3 | D-02 (ADR BẮT KHÁC) | Body response/lỗi theo starter | thiếu ppuId → cũ 400 body rỗng / mới 400 INVALID_REQUEST; message[0]/reason theo starter |
Client không đọc body 400 rỗng |
| 4 | D-04 (MƠ HỒ) | @Transactional không readOnly → đọc DB chính |
không khác (nếu suy luận đúng) | Xác nhận code cũ đọc DB chính; nếu cũ đọc replica có thể đổi sang readOnly=true |
| 5 | D-05 (PHỤ THUỘC NGOÀI) | Không chuyển kiểm gói dịch vụ | công ty hết gói → cũ 400 ACCOUNT_EXPIRED / mới trả tồn |
Tầng nào (gateway/service) kiểm gói |
| 6 | D-06 (ADR BẮT KHÁC) | Lỗi DB → SystemException(EXCEPTION_ERROR) |
lỗi kết nối → cũ 417 / mới 500, cùng mã EXCEPTION_ERROR |
Client không phụ thuộc HTTP 417 |
| 7 | spec-review | Spec qua 1 lần review, các R-xx đã sửa theo MAJOR: R-03, R-07, R-08 (F-spec-1, F-spec-2) | — | Đọc kỹ R-03, R-07, R-08 trong spec.md |
4. Finding đã xác nhận
Không có finding CRITICAL/MAJOR. Finding MINOR (không qua xác minh, chuyển cho người — mục 3 dòng 2):
F-logic-1
- Mức độ: MINOR · Loại: architecture · Quy tắc: R-03, R-04, R-06, R-11
- Code mới:
ProductStockDetailJdbcRepository.java:19-86;InventoryRelationalRepository.java:51-57 - Mô tả: spec mục 5 ghi SQL nằm trong
InventoryJpaRepositoryCustomImpl; code tạo lớp@Repositoryriêng. Không đổi kết quả. - Đề xuất: chuyển vào lớp cũ hoặc ghi lại spec mục 5. Không bắt buộc cho G5.
5. Finding bị loại
| Finding | Lý do loại |
|---|---|
| (không có) |
6. Xử lý của người
| Vấn đề | Cổng | Chỉ thị |
|---|---|---|
| (không có vấn đề làm trượt cổng máy; G4 chờ người kiểm Sonar) | G4 |
7. So với vòng trước
| Vấn đề | Vòng trước | Vòng này |
|---|---|---|
| (vòng đầu) | — | — |
8. Thay đổi trong repo đích
16 file (verify/round-1/changed-files.md), đều trong src/main, src/test:
- Mới (main):
presentation/web/inventory/InventoryController,InventoryWebMapper,dto/response/ProductStockDetailResponse;domain/inventory/result/ProductStockDetailResult;infrastructure/relational/inventory/jpa/ProductStockDetailJdbcRepository. - Sửa (main):
InventoryQueryService,InventoryRepository,InventoryErrorCode,InventoryRelationalRepository,i18n/messages_vi|en.properties. - Test mới:
InventoryControllerTest,InventoryQueryServiceTest,ProductStockDetailJdbcRepositoryTest,InventoryRelationalRepositoryTest. - Test sửa ngoài unit (cần thiết):
WarehouseTransferServiceTest— 1 dòng dựngInventoryQueryService.
9. Đề xuất bổ sung kinh nghiệm (/mig-learn gom vào proposal để người duyệt)
| Đề xuất | Đưa vào đâu |
|---|---|
Response record có field null/rỗng phải giữ key như monolith → @JsonInclude(ALWAYS) vì mapper starter NON_EMPTY (DataConverterAutoConfiguration.java:51); test serialize bằng buildObjectMapper() |
lessons.md 1b + legacy-facts/target-cheatsheet |
Thêm method vào InventoryJpaRepositoryCustomImpl làm PMD CyclomaticComplexity (tổng lớp > 50) đỏ — truy vấn mới đặt ở lớp JDBC riêng; ghi vào spec mục 5 ngay từ đầu |
target-cheatsheet.md mục 4 |
Truy vấn native có thể test thật trên H2 MODE=MSSQLServer (bảng tối thiểu) thay vì chỉ mock — vẫn UNVERIFIED trên MSSQL |
target-cheatsheet.md mục 5 |