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

Kho · warehouse/create · api

POST/api/client/page/warehouse/create

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

Báo cáo sai lệch — warehouse/create — 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
  • Tầng rủi ro: A (tự động) → người cần đọc: spec + báo cáo + toàn bộ diff
  • Số quy tắc: 16 · PASS 10 · DEVIATION có chủ đích 5 (R-01, R-02, R-12: định dạng body/kiểm công ty; R-15: khoá; R-03: lỗi hệ thống 500) · DEVIATION KHÔNG chủ đích 0 · UNVERIFIED 1 (R-16 không chuyển) — thêm: phần chạy thật trên MSSQL/Redis của R-03, R-09, R-11, R-14, R-15 chưa kiểm (IT/golden chưa cấu hình)
  • Coverage thấp nhất: F-01 dòng 100% / nhánh 97,9%
  • Finding logic: CRITICAL 0 · MAJOR 0 (đã xác nhận) · MINOR 1 · UNSURE 0
  • Nghi vấn bug code cũ (mục 3c): 10 (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 2 lần, chưa có người duyệt) · Số vòng: 2 / 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 Kiến trúc ADR (mvnw verify: build, test, ArchUnit, Checkstyle/PMD/SpotBugs) ✅ verify/round-2/build.md — 537 test, ArchUnit 36/36, 0 Checkstyle/PMD/SpotBugs
G2 Test khớp test-plan, mọi R-xx có test ✅ verify/round-2/oracle.md — 52/52 TC khớp
G3 Coverage mỗi luồng (dòng ≥ 80%, nhánh ≥ 70%) ✅ verify/round-2/coverage.md
G4 0 issue Sonar (người kiểm bằng SonarQube for IDE) CHỜ NGƯỜI sonar-ide.md (CHƯA KIỂM)
G5 0 finding logic CRITICAL/MAJOR đã xác nhận ✅ verify/round-2/review-logic.md (chỉ 1 MINOR — không cần xác minh)
G6 Không lách cổng, không ghi ngoài phạm vi ✅ verify/round-2/gates.md; 36/36 file 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…GM-03 trong test-plan.md)

Coverage theo luồng

Luồng Tên % dòng % nhánh
F-01 Tạo kho mới (id không gửi) 100,0% (267/267) 97,9% (94/96)
F-02 /create gửi kèm id → sửa kho 100,0% (242/242) 98,8% (79/80)

2. Ma trận truy vết

Quy tắc Tầng Code mới Test Golden Kết luận
R-01 B WarehouseController, WarehouseSaveRequest TC-01, TC-02 — DEVIATION (có chủ đích, D-02: định dạng body lỗi)
R-02 A WarehouseManagementService.saveWarehouse → CurrentCompanyService TC-03, TC-04 — DEVIATION (có chủ đích, D-01)
R-03 A generateCode, SequenceSeedJdbcRepository, LegacyRedisSequenceReader TC-05…TC-13 GM-01, GM-03 DEVIATION (có chủ đích, D-03: 417→500); nhánh Redis/DB thật UNVERIFIED
R-04 B saveWarehouse TC-14 — PASS
R-05 B Warehouse.copyFrom TC-15, TC-17 — PASS
R-06 B Warehouse.copyFrom TC-15, TC-16, TC-17 — PASS
R-07 B Warehouse.create TC-15, TC-46 — PASS
R-08 B WarehouseText.normalizedName TC-18, TC-19 — PASS
R-09 B WarehouseDuplicatePolicy, WarehouseManagementService.duplicateRows TC-20…TC-29 GM-02 PASS (unit); flush Hibernate cũ UNVERIFIED
R-10 B Warehouse.validateDefaultWarehouse TC-30…TC-34 — PASS (NPE → 500 theo D-03)
R-11 B Warehouse.create/update, WarehouseText, WarehouseJpaMapper, adapter TC-29, TC-35…TC-39, TC-50 GM-01, GM-02 PASS (unit); DB thật UNVERIFIED
R-12 B WarehouseController, WarehouseResponse TC-40…TC-42 — DEVIATION (có chủ đích, D-02: reason là mã)
R-13 B saveWarehouse TC-43 — PASS
R-14 B validateNoProcessingBill, BillRelationalAdapter TC-44…TC-46, TC-52 — PASS (unit); SQL thật UNVERIFIED
R-15 A WarehouseRelationalRepository.lockCompanyWarehouses TC-47, TC-48 (+EXTRA-1) — DEVIATION (có chủ đích, D-05); khoá trên MSSQL thật UNVERIFIED
R-16 A — TC-49 — UNVERIFIED (không chuyển, D-16)

3. Người cần xem

# Vị trí Vì sao cần người xem
1 Toàn bộ diff verify/round-2/changes.diff (36 file) Tầng A
2 WarehouseRelationalRepository.java — LOCK_COMPANY_WAREHOUSES_SQL, lockCompanyWarehouses Khoá sp_getapplock (D-05) đã sửa ở lần sửa 1 (F-logic-1 vòng 1, CRITICAL) nhưng mới kiểm bằng mock — cần chạy một lần trên MSSQL thật trước khi dùng; nếu khoá hỏng thì mọi request /create lỗi 500
3 R-16 / D-16 API mới không chặn tài khoản hết hạn/chưa thanh toán gói như backend cũ
4 Warehouse.update, WarehouseManagementService.duplicateRows Mô phỏng hành vi Hibernate 5 cũ (flush trước native query, @PreUpdate khi dirty) — chưa kiểm trên DB (GM-02)
5 LegacyRedisSequenceReader, SequenceSeedJdbcRepository Đọc khoá Redis cũ {comId}_SEQ (D-07) — chưa kiểm trên Redis thật (GM-03)
6 Câu SQL native (TOP, sp_getapplock) Chỉ chạy trên MSSQL; nếu bật routing PostgreSQL (ADR-0201, đang comment trong application-dev.yml:174) sẽ lỗi
7 F-logic-1 vòng 2 (MINOR) Tràn int ở giá trị biên khoá Redis cũ — xem mục 4
8 decisions.md#D-13 Câu chữ ví dụ còn ghi NULL_EXCEPTION; quyết định đúng (D-03, R-10, code) là EXCEPTION_ERROR — người sửa câu chữ
9 G4 Chưa kiểm Sonar

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 Tạo kho mới 9 / 1 (D-01) / 1 (D-16) / 1 (khoá D-05) Không thực chất (cleanText trong Warehouse.create) Khoá phụ thuộc implicit transaction mssql-jdbc, chỉ có test mock; khoá được giữ trong lúc gọi Redis; nhánh Redis cũ + tràn int; WH1 + sellable null → 500
F-02 /create có id → sửa 9 / 1 (D-01) / 1 (D-16) / 1 (khoá D-05) Không Warehouse.update mô phỏng dirty check (9 trường); duplicateRows thay dòng của chính kho; mapper.apply chép đè cả null; map status bit↔Integer; tên trong lỗi bill là tên đã làm sạch

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

B-01 Gọi API "thêm kho" kèm id lại sửa kho đó, và kho bị ngừng hoạt động nếu quên gửi trạng thái

  • Mức nghi ngờ: TRUNG BÌNH — chắc chắn code cũ làm vậy; chỉ không chắc frontend có bao giờ gửi id vào /create không.
  • Ở đâu: code cũ easyposbase:src/main/java/sds/ep/baseservice/services/impl/BaseWarehouseServiceImpl.java:174-182, easyposbase:.../dto/warehouse/WarehouseSaveRequest.java:75-77 → code mới (giữ nguyên) src/main/java/com/softdreams/easypos/warehouse/domain/warehouse/model/Warehouse.java (update, copyFrom), .../application/warehouse/WarehouseManagementService.java (saveWarehouse)
  • Code cũ đang làm gì: API thêm kho và API sửa kho dùng chung một hàm lưu. Nếu body có id, hàm này tìm kho đó và chép đè mọi trường từ request lên, kể cả trường để trống. Trường "đang hoạt động" để trống được hiểu là "ngừng hoạt động".
  • Ví dụ cụ thể: kho 5 "Kho A", SĐT 0901, đang hoạt động. Gửi POST /create {"id":5,"comId":10,"name":"Kho A"} → hệ thống cũ (và mới) không tạo kho mới mà sửa kho 5: SĐT, địa chỉ, mô tả bị xoá, kho chuyển sang ngừng hoạt động, trả "Cập nhật thành công!". Nếu đúng nghiệp vụ thì /create lẽ ra tạo kho mới (hoặc từ chối id), và trạng thái để trống lẽ ra giữ nguyên.
  • Vì sao nghi là sai: tên API là "create"; một trường bỏ trống mà làm ngừng kho là tác dụng phụ khó đoán.
  • Ảnh hưởng nếu đúng là bug: client gửi nhầm id (ví dụ form sao chép kho) sẽ sửa/ngừng kho đang dùng; kho ngừng thì không bán/xuất được. Hiếm gặp với /create, nhưng cùng logic chạy ở PUT /update (unit warehouse/update) nơi việc quên gửi status dễ xảy ra hơn.
  • Đã xử lý khi chuyển: GIỮ nguyên hành vi cũ. Test khoá hành vi này: TC-17 (WarehouseTest#updateOverwritesWithNullsAndKeepsCode, WarehouseManagementServiceTest#updateThroughCreateEndpoint), TC-41 (WarehouseControllerTest#updateReturnsSuccessUpdate).
  • Nếu muốn sửa: ở WarehouseController.createWarehouse bỏ id hoặc trả 400 khi có id; ở Warehouse.update coi status null là giữ nguyên. Đổi TC-17, TC-41 theo. Monolith còn chạy song song vẫn giữ hành vi cũ → hai hệ thống lệch nhau cho tới khi tắt API cũ. Không cần sửa dữ liệu cũ.
  • Liên quan: D-09, R-05, R-13, R-14

B-02 Kiểm trùng tên/mã kho phân biệt hoa thường và dấu cách thừa nên vẫn lưu được kho trùng tên

  • Mức nghi ngờ: TRUNG BÌNH — code rõ ràng; không rõ nghiệp vụ có cố ý cho "kho a" khác "Kho A" không.
  • Ở đâu: code cũ easyposbase:.../BaseWarehouseServiceImpl.java:195-205,230-232, easyposmodel:.../util/CleanTextListener.java:14-34 → code mới (giữ nguyên) src/main/java/com/softdreams/easypos/warehouse/domain/warehouse/policy/WarehouseDuplicatePolicy.java
  • Code cũ đang làm gì: so tên/mã gửi lên nguyên văn với tên/mã đã lưu (đã được làm sạch: bỏ khoảng trắng thừa). Chỉ coi là trùng khi giống hệt từng ký tự, kể cả hoa/thường.
  • Ví dụ cụ thể: công ty đã có "Kho A". Tạo kho tên "Kho A " (thừa một dấu cách) → không bị báo trùng → lưu thành "Kho A" → công ty có hai kho "Kho A". Tạo "kho a" → cũng được lưu.
  • Vì sao nghi là sai: luật "tên kho không trùng" bị lách chỉ bằng một dấu cách; dữ liệu sau khi lưu lại trùng hẳn.
  • Ảnh hưởng nếu đúng là bug: danh sách kho có tên trùng, người dùng chọn nhầm kho khi nhập/xuất. Xảy ra khi người dùng gõ thừa dấu cách — khá dễ gặp.
  • Đã xử lý khi chuyển: GIỮ nguyên. Test khoá: TC-24 (WarehouseDuplicatePolicyTest#comparisonIsExactAndCaseSensitive).
  • Nếu muốn sửa: trong WarehouseDuplicatePolicy.validate so giá trị đã cleanTextReturnNull và không phân biệt hoa thường; đổi TC-24. Monolith vẫn so kiểu cũ → nên sửa cả hai bên. Dữ liệu trùng đã có cần rà tay.
  • Liên quan: D-11, R-09

B-03 Khi sửa kho (qua /create có id), đổi tên thành tên kho khác kèm dấu cách thừa thì lọt kiểm trùng

  • Mức nghi ngờ: TRUNG BÌNH — logic "đếm 2 mới báo trùng" chỉ đúng nhờ tác dụng phụ của ORM (Hibernate ghi bản sửa xuống trước câu kiểm); kết quả runtime cũ chưa kiểm trên DB.
  • Ở đâu: code cũ easyposbase:.../BaseWarehouseServiceImpl.java:175-205,235-245, easyposbase:.../repositories/BaseWarehouseRepository.java:37-38 → code mới (giữ nguyên) .../application/warehouse/WarehouseManagementService.java (duplicateRows), .../domain/warehouse/policy/WarehouseDuplicatePolicy.java
  • Code cũ đang làm gì: khi sửa, chỉ báo trùng nếu đếm được 2 kho trùng (coi 1 là chính kho đang sửa). Dòng của chính kho mang tên mới đã làm sạch.
  • Ví dụ cụ thể: kho 5 "Kho A", kho 6 "Kho B". Sửa kho 5 thành "Kho B" → bị chặn (đúng). Sửa kho 5 thành "Kho B " (thừa dấu cách) → dòng kho 5 thành "Kho B" ≠ "Kho B ", kho 6 "Kho B" ≠ "Kho B " → đếm 0 → lưu → hai kho "Kho B".
  • Vì sao nghi là sai: như B-02, và luật phụ thuộc vào thời điểm ORM ghi dữ liệu chứ không nằm trong logic.
  • Ảnh hưởng nếu đúng là bug: như B-02, ở thao tác sửa.
  • Đã xử lý khi chuyển: GIỮ nguyên. Test khoá: TC-27 (WarehouseManagementServiceTest#renamingToAnotherWarehouseNameIsRejected), TC-28 (#trailingSpaceSlipsThroughDuplicateCheck), TC-26 (WarehouseDuplicatePolicyTest#updateFailsWhenCounterReachesTwo).
  • Nếu muốn sửa: loại dòng có id của chính kho khỏi danh sách và báo trùng từ 1, so giá trị đã làm sạch; đổi TC-26…TC-28.
  • Liên quan: D-12, R-09, R-11

B-04 Dữ liệu bộ đếm Redis cũ bị hỏng làm công ty không tạo được kho nào nữa

  • Mức nghi ngờ: THẤP — chỉ xảy ra nếu khoá Redis cũ {comId}_SEQ còn tồn tại và hỏng; không biết dữ liệu thật còn không.
  • Ở đâu: code cũ easyposbase:.../services/BaseSequenceService.java:266-283 → code mới (giữ nguyên) .../infrastructure/cache/LegacyRedisSequenceReader.java, .../infrastructure/relational/sequence/SequenceSeedJdbcRepository.java
  • Code cũ đang làm gì: lần đầu sinh mã kho cho công ty, đọc số cũ trong Redis {comId}_SEQ. Nếu giá trị đó hỏng (rỗng, chữ, số thập phân…) thì báo lỗi hệ thống trước khi lưu bộ đếm mới, nên lần sau lại đọc đúng giá trị hỏng đó.
  • Ví dụ cụ thể: Redis 10_SEQ = {"warehouse":"abc"}, công ty 10 chưa có bộ đếm WH mới → mọi lần tạo kho đều trả "Lỗi hệ thống" (cũ 417, mới 500) cho tới khi có người sửa Redis. Lẽ ra nên bỏ qua giá trị hỏng và tính từ số kho hiện có.
  • Vì sao nghi là sai: một dữ liệu cache hỏng chặn vĩnh viễn một nghiệp vụ.
  • Ảnh hưởng nếu đúng là bug: công ty bị ảnh hưởng không thêm được kho; hiếm.
  • Đã xử lý khi chuyển: GIỮ nguyên. Test khoá: TC-10 (LegacyRedisSequenceReaderTest#corruptedLegacyValueFails).
  • Nếu muốn sửa: trong LegacyRedisSequenceReader.findWarehouseSequence trả rỗng thay vì ném lỗi; đổi TC-10.
  • Liên quan: D-07, R-03

B-05 Sửa kho không tồn tại trả lỗi máy chủ (500) thay vì "không tìm thấy"

  • Mức nghi ngờ: THẤP — có thể cố ý.
  • Ở đâu: code cũ easyposbase:.../BaseWarehouseServiceImpl.java:175-177 → code mới (giữ nguyên) .../application/warehouse/WarehouseManagementService.java (SystemException(WAREHOUSE_NOT_FOUND))
  • Code cũ đang làm gì: id không thuộc công ty → lỗi kiểu "lỗi máy chủ" (HTTP 500) với nội dung "Kho hàng không tồn tại".
  • Ví dụ cụ thể: {"id":999,"comId":10,"name":"Kho A"} → 500. Lẽ ra 404 hoặc 400.
  • Vì sao nghi là sai: lỗi do dữ liệu người gửi, không phải lỗi máy chủ; giám sát sẽ tính nhầm là sự cố.
  • Ảnh hưởng nếu đúng là bug: cảnh báo giả trên giám sát; client hiển thị "lỗi hệ thống".
  • Đã xử lý khi chuyển: GIỮ nguyên. Test khoá: TC-43 (WarehouseManagementServiceTest#missingWarehouseIsSystemError).
  • Nếu muốn sửa: đổi sang NotFoundException; đổi TC-43.
  • Liên quan: D-04, R-13

B-06 Kho mặc định WH1 tạo/sửa mà không gửi "cho bán" thì báo lỗi hệ thống

  • Mức nghi ngờ: THẤP — rõ là lỗi lập trình (NullPointerException), nhưng hiếm gặp.
  • Ở đâu: code cũ easyposbase:.../BaseWarehouseServiceImpl.java:219-226 → code mới (giữ nguyên) .../domain/warehouse/model/Warehouse.java (validateDefaultWarehouse)
  • Code cũ đang làm gì: kho mã WH1 phải "đang hoạt động" và "cho bán"; nếu trường "cho bán" để trống thì chương trình lỗi null.
  • Ví dụ cụ thể: công ty chưa có kho nào, bộ đếm cấp WH1, gửi {"comId":10,"name":"Kho chính"} → cũ 417, mới 500 "Lỗi hệ thống". Lẽ ra coi trống là "cho bán" hoặc báo lỗi 400 rõ ràng.
  • Vì sao nghi là sai: lỗi null không phải luật nghiệp vụ.
  • Ảnh hưởng nếu đúng là bug: hiếm (WH1 thường được tạo tự động khi đăng ký công ty).
  • Đã xử lý khi chuyển: GIỮ nguyên (mã EXCEPTION_ERROR, HTTP 500 theo D-03). Test khoá: TC-31 (WarehouseTest#defaultWarehouseWithoutSellableIsSystemError, WarehouseManagementServiceTest#defaultWarehouseWithoutSellableIsSystemError).
  • Nếu muốn sửa: trong validateDefaultWarehouse đổi nhánh sellable == null; đổi TC-31.
  • Liên quan: D-13, D-03, R-10

B-07 Tên kho chỉ toàn dấu cách vẫn tạo được, lưu tên rỗng

  • Mức nghi ngờ: THẤP.
  • Ở đâu: code cũ easyposbase:.../dto/warehouse/WarehouseSaveRequest.java:14-15 (@NotEmpty) → code mới (giữ nguyên) .../presentation/web/warehouse/dto/request/WarehouseSaveRequest.java
  • Code cũ đang làm gì: chỉ chặn tên null/rỗng; tên " " qua được rồi bị làm sạch thành rỗng.
  • Ví dụ cụ thể: {"comId":10,"name":" "} → 200, kho mới tên "", normalized_name NULL. Lẽ ra báo "Tên kho hàng trống".
  • Vì sao nghi là sai: kho không có tên hiển thị.
  • Ảnh hưởng nếu đúng là bug: danh sách kho có dòng trống.
  • Đã xử lý khi chuyển: GIỮ nguyên. Test khoá: TC-02 (WarehouseSaveRequestValidationTest#nameMustNotBeEmpty).
  • Nếu muốn sửa: đổi @NotEmpty → @NotBlank; đổi TC-02.
  • Liên quan: D-15, R-01

B-08 Mã kho chỉ toàn dấu cách được lưu rỗng; tên chuẩn hoá không chứa mã mặc định

  • Mức nghi ngờ: THẤP.
  • Ở đâu: code cũ easyposbase:.../BaseWarehouseServiceImpl.java:183-189 → code mới (giữ nguyên) .../domain/warehouse/model/Warehouse.java (copyFrom)
  • Code cũ đang làm gì: chỉ thay SKU trống bằng mã kho khi SKU null hoặc rỗng; " " giữ nguyên rồi bị làm sạch thành rỗng. Tên chuẩn hoá tính từ SKU gửi lên, không phải SKU cuối cùng.
  • Ví dụ cụ thể: {"name":"Kho A","sku":" "}, mã WH8 → SKU lưu "". {"name":"Kho A"} → SKU "WH8" nhưng normalized_name="khoa" (không có |wh8). Lẽ ra SKU = WH8 và tên chuẩn hoá có mã.
  • Vì sao nghi là sai: kho mất mã hiển thị; tìm kho theo mã qua tên chuẩn hoá không ra.
  • Ảnh hưởng nếu đúng là bug: nhỏ; ảnh hưởng tìm kiếm.
  • Đã xử lý khi chuyển: GIỮ nguyên. Test khoá: TC-16 (WarehouseTest#skuDefaultsOnlyWhenNullOrEmpty), TC-19 (#normalizedNameIgnoresDefaultSku).
  • Nếu muốn sửa: trim SKU trước khi xét mặc định, tính tên chuẩn hoá từ SKU cuối; đổi TC-16, TC-19.
  • Liên quan: D-10, R-06, R-08

B-09 Tạo kho bị từ chối vẫn làm nhảy số mã kho

  • Mức nghi ngờ: THẤP — không làm sai dữ liệu.
  • Ở đâu: code cũ easyposbase:.../BaseWarehouseServiceImpl.java:180,190-207 → code mới (giữ nguyên) .../application/warehouse/WarehouseManagementService.java (generateCode chạy trước kiểm trùng)
  • Code cũ đang làm gì: cấp số mã (tăng bộ đếm Redis) trước khi kiểm trùng; bị từ chối thì số đã cấp mất luôn.
  • Ví dụ cụ thể: kho cuối WH7; tạo "Kho A" bị báo trùng tên 3 lần rồi đổi tên → kho mới là WH11 thay vì WH8.
  • Vì sao nghi là sai: mã nhảy cóc, người dùng có thể thắc mắc.
  • Ảnh hưởng nếu đúng là bug: chỉ thẩm mỹ.
  • Đã xử lý khi chuyển: GIỮ nguyên. Test khoá: TC-14 (WarehouseManagementServiceTest#duplicateNameStillConsumesSequence).
  • Nếu muốn sửa: kiểm trùng trước rồi mới sinh mã; đổi TC-14.
  • Liên quan: D-08, R-03, R-04

B-10 Sinh mã kho chỉ kiểm trùng theo SKU nên có thể cấp mã đã có

  • Mức nghi ngờ: THẤP — chỉ khi bộ đếm Redis lệch dữ liệu.
  • Ở đâu: code cũ easyposbase:.../services/BaseSequenceService.java:65,436-443 → code mới (giữ nguyên) .../application/warehouse/WarehouseManagementService.java (generateCode → existsBySku)
  • Code cũ đang làm gì: khi sinh WH<n>, chỉ hỏi "đã có kho nào SKU = WH<n> chưa", không hỏi theo cột mã.
  • Ví dụ cụ thể: kho 3 có mã WH3, SKU "KHO-TONG"; bộ đếm bị đặt lại về 2 → lần tạo sau sinh WH3, không thấy SKU WH3 → kho mới cũng mã WH3.
  • Vì sao nghi là sai: hai kho trùng mã.
  • Ảnh hưởng nếu đúng là bug: hiếm.
  • Đã xử lý khi chuyển: GIỮ nguyên. Test khoá: TC-06 (WarehouseManagementServiceTest#retriesWhenCodeIsUsedAsSku).
  • Nếu muốn sửa: kiểm cả cột code; thêm TC.
  • Liên quan: D-14, R-03

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-01 (LỖI KỸ THUẬT) Kiểm comId = công ty trong token comId công ty khác → cũ 200 tạo kho / mới 400 COMPANY_NOT_OF_CURRENT_USER; comId ≤ 0 → mới 400 INVALID_COMPANY Đồng ý chặn ghi chéo công ty
2 D-02 (ADR BẮT KHÁC) Body theo BaseResponseDTO của starter; validate thủ công Guard.validateInput Trùng tên → cũ reason="Tên kho hàng đã tồn tại" / mới reason="WAREHOUSE_NAME_DUPLICATE" (text ở message[0].message); validate → reason="INVALID_REQUEST"; JSON hỏng → cũ 400 body rỗng / mới 400 INVALID_REQUEST; thành công reason="SUCCESS_CREATE" Frontend đọc mã ở message[].code, không dựa vào reason
3 D-03 (ADR BẮT KHÁC) Lỗi hệ thống 417 → 500, giữ mã EXCEPTION_ERROR WH1 thiếu sellable, hết 10 lần sinh mã, Redis cũ hỏng → cũ 417 / mới 500; DB lỗi khi đếm kho → mới 500 UNCERTAIN_ERROR, Redis không ghi Frontend xử lý 500 như 417
4 D-05 (LỖI KỸ THUẬT) Khoá sp_getapplock theo công ty (phạm vi transaction, chờ 10 s); lần sửa 1 thêm đọc bảng trước EXEC Hai request đồng thời cùng tên → cũ 2 kho / mới 1 kho + 400; không lấy được khoá trong 10 s → mới 500 Đồng ý cơ chế; chạy thử trên MSSQL thật
5 D-06 (PHỤ THUỘC NGOÀI) Dùng nguyên SequenceService (vùng lõi) Khởi tạo bộ đếm đồng thời có thể cấp trùng số — như cũ Có làm việc riêng sửa SequenceService (HSETNX) không
6 D-16 (PHỤ THUỘC NGOÀI) Không chuyển kiểm gói dịch vụ Gói hết hạn → cũ 400 ACCOUNT_EXPIRED / mới 200 tạo kho Chọn tầng đảm nhận (gateway / starter / interceptor chung)
7 spec-reviewer lần 1–2 (11 finding) Đã sửa spec/decisions trước khi viết test-plan (chi tiết spec-review/round-1.md, round-2.md) Không có thay đổi spec/test-plan sau khi viết — auto-changes.md không có dòng nào Đọc 2 file review nếu muốn biết spec đã đổi gì
8 F-logic-1 vòng 2 (MINOR, không sửa trong vòng lặp) Giữ cộng long Redis {"warehouse":2147483647} → cũ mã WH-2147483648 (tràn) / mới WH2147483648 Chấp nhận khác biệt hay sửa về int
9 Phạm vi unit Chỉ chuyển POST /create; mang theo nhánh sửa của save() vì /create có id đi vào đó PUT /update chưa chuyển (unit warehouse/update); thư mục cũ migrations/api-warehouse-create/ (người đã chốt "gộp update") giữ nguyên Chạy /mig-auto cho PUT /update hay gộp; xoá thư mục cũ nếu không dùng
10 decisions.md#D-13 câu chữ Không sửa (vòng lặp không được sửa decisions) Ví dụ ghi NULL_EXCEPTION, đúng là EXCEPTION_ERROR Sửa câu chữ
11 Thứ tự ghi F-02 UPDATE lúc commit thay vì lúc flush giữa transaction (cũ) Kết quả cuối giống nhau; không có câu nào đọc lại dòng này giữa chừng Không cần làm gì nếu đồng ý

4. Finding đã xác nhận

Không có finding CRITICAL/MAJOR ở vòng 2. Finding MINOR (không qua xác minh):

F-logic-1 (vòng 2)

  • Mức độ: MINOR
  • Loại: parity
  • Quy tắc: R-03
  • Code mới: src/main/java/com/softdreams/easypos/warehouse/infrastructure/cache/LegacyRedisSequenceReader.java:63-73, .../infrastructure/relational/sequence/SequenceSeedJdbcRepository.java:62-66
  • Code cũ: easyposbase:src/main/java/sds/ep/baseservice/services/BaseSequenceService.java:275-276
  • Mô tả: cũ cộng mốc bằng int (tràn ở Integer.MAX_VALUE), mới cộng bằng long.
  • Kịch bản tái hiện: Redis 10_SEQ = {"warehouse":2147483647} → cũ WH-2147483648 | mới WH2147483648.
  • Đề xuất sửa: cộng bằng int, hoặc ghi D-xx chấp nhận.
  • Độ tin cậy: cao

5. Finding bị loại

Finding Lý do loại
(không có)

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

Không có vấn đề nào đang làm trượt cổng máy. Nếu muốn AI xử lý tiếp, ghi chỉ thị rồi chạy /mig-run warehouse/create.

Vấn đề Cổng Chỉ thị
F-logic-1 vòng 2 (MINOR) — tràn int ở mốc Redis cũ — (không chặn)
G4 — chưa kiểm Sonar G4

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

Vấn đề Vòng trước Vòng này
F-logic-1 (vòng 1, CRITICAL) — sp_getapplock chạy khi chưa có transaction CONFIRMED ĐÃ HẾT (reviewer vòng 2 xác nhận đã sửa; vẫn cần chạy trên MSSQL thật)
TC-12 lệch (G2) lệch ĐÃ HẾT
F-logic-1 (vòng 2, MINOR) — tràn int — MỚI (có từ đầu, không do lần sửa)

8. Thay đổi trong repo đích

36 file, tất cả trong src/main, src/test (verify/round-2/changed-files.md):

  • Main mới (16): WarehouseController, WarehouseWebMapper, WarehouseSaveRequest, WarehouseResponse, WarehouseManagementService, SaveWarehouseCommand, WarehouseResult, WarehouseErrorCode, Warehouse, WarehouseText, WarehouseNameSku, WarehouseAudit, WarehouseDuplicatePolicy, WarehouseNameSkuView, WarehouseJpaMapper, LegacyRedisSequenceReader.
  • Main sửa (8): WarehouseRepository, SequenceCode, BillPort, WarehouseJpaEntity, WarehouseJpaRepository, WarehouseRelationalRepository, SequenceSeedJdbcRepository, BillRelationalAdapter; i18n messages_vi/en.properties (9 key mỗi file).
  • Test mới (9) + test sửa (1: WarehouseRelationalRepositoryTest).
  • Ảnh hưởng ngoài unit: SequenceSeedJdbcRepository (nhánh WH mới; NK/XK/CK không đổi — TC-11), WarehouseJpaEntity thêm cột + @DynamicUpdate (các truy vấn đọc kho cũ không đổi), BillPort thêm method. Không có file ngoài phạm vi dự kiến.

9. Đề xuất bổ sung kinh nghiệm (người duyệt rồi tự chép sang knowledge/)

Đề xuất Đưa vào đâu
sp_getapplock @LockOwner='Transaction' cần @@TRANCOUNT > 0; pool auto-commit: false chỉ mở transaction ngầm khi có lệnh đọc/ghi bảng → không để khoá là lệnh SQL đầu tiên, không dùng BEGIN TRAN lessons.md
Code cũ dùng native query sau khi sửa entity trong cùng transaction: Hibernate 5 (bootstrap JPA) flush trước native query → khi port phải mô phỏng (dòng của chính entity mang giá trị mới, @PreUpdate chỉ khi dirty) lessons.md / review-criteria.md
API "create" dùng chung hàm save() với update: luôn kiểm nhánh có id khi chuyển lessons.md (bước spec)
Lỗi validate phải trả đủ mọi vi phạm như BaseCommon.validateInput cũ → dùng Guard.validateInput, không dùng @Valid review-criteria.md

Nguồn của trang này

  • Báo cáo sai lệch migrations/warehouse/create/report.md vòng 2 · sha256 7d38c0aca614

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