Sub-task EP-08-T04-S01 Yuqori 05_customers erpbom-backend

Hujjat yuklash (R42 proxy) + ro'yxat

Bajarildi
Status:

Tavsif

`customer_document.upload` bilan PDF/rasm yuklash; `doc_type` = `passport` | `receipt_note` | `other`.

Texnik ko'rsatma

Agent uchun

🔴 Mavjud `FileUploadService` ISHLATILADI (09_auth R42 proxy: hajm/MIME/**magic bytes** omborga yozishdan OLDIN tekshiriladi). Yangi upload qatlami YOZILMAYDI. `ObjectKeyGenerator` — `<domen>/<yil>/<oy>/<uuid>.<ext>` (tenant prefiksi YO'Q — AR-7). Saqlanadi: `file_key`, `mime_type`, `size_bytes`, `doc_type`, ixtiyoriy `contract_id`. 🔴 Original fayl nomi SAQLANMAYDI (09_auth Q29 = C). `receipt_note` turini QO'LDA yuklashga ruxsat beriladi (tilxat generatsiyasi T05 da avtomatik yozadi — ikkalasi bir jadvalga tushadi, ziddiyat yo'q).

Qabul mezonlari (DoD)

3 / 3 bajarildi

  • MIME/magic bytes mos kelmagan fayl omborga YOZILMAY rad etiladi (test: kengaytmasi .pdf, ichi boshqa)

    qa-ep-08-t04-s01 · 1 о аввал

  • Yuklangan qator `mime_type` va `size_bytes` bilan to'ladi; original fayl nomi hech qayerda saqlanmaydi

    qa-ep-08-t04-s01 · 1 о аввал

  • `customer_document.upload` huquqisiz chaqiruv 403

    qa-ep-08-t04-s01 · 1 о аввал

O'zgargan fayllar

7 ta

  • modified src/test/java/uz/erpbom/customers/controller/CustomerDocumentControllerIntegrationTest.java
  • modified src/main/java/uz/erpbom/customers/service/CustomerDocumentService.java
  • modified src/main/java/uz/erpbom/customers/repository/CustomerDocumentRepository.java
  • modified src/main/java/uz/erpbom/customers/mapper/CustomerDocumentMapper.java
  • modified src/main/java/uz/erpbom/customers/entity/CustomerDocument.java
  • modified src/main/java/uz/erpbom/customers/dto/CustomerDocumentResponse.java
  • modified src/main/java/uz/erpbom/customers/controller/CustomerDocumentController.java

Izoh qoldirish

Tarix

21 yozuv

  • ✎

    finalize-ep-08 yangiladi

    Yangilandi: pr_url

  • ⇄

    qa-ep-08-t04-s01 statusni o'zgartirdi Review → Bajarildi

  • 💬

    qa-ep-08-t04-s01 izoh qoldirdi

    QA qayta tekshiruv (2-marta) — OTDI. Izolyatsiyalangan worktree (ef3e775) da uchala mutant qayta kiritildi, HAMMASI OLDI: (a) CustomerDocumentService.java:103 setMimeType("application/pdf") -> KILLED (uploadingDifferentFileTypesPersistsDistinctMimeTypeAndSizeBytes:220). javap: ldc #116 // String application/pdf setMimeType oldidan — mutatsiya bytecode da tasdiqlandi. (b) CustomerDocumentService.java:104 setSizeBytes(27L) -> KILLED (ayni test). javap: ldc2_w #122 // long 27l -> Long.valueOf -> setSizeBytes. (c) CustomerDocumentRepository.java:34 ORDER BY d.uploadedAt DESC->ASC -> KILLED (listingDocumentsOrdersByUploadedAtDescending). javap -v constant pool: "...ORDER BY d.uploadedAt ASC" — @Query matni haqiqatan almashgan. Test sog?ligi: PNG_BYTES fixture PDF_BYTES dan ham MIME (image/png vs application/pdf), ham uzunlik (76 vs 27 bayt) bilan farq qiladi; assert?lar har fixture?ning O?Z qiymatiga (PDF_BYTES.length / PNG_BYTES.length) bog?langan + DB dan qayta o?qib tasdiqlanadi. Tartib testi uploaded_at ni id tartibiga TESKARI qo?yadi (1-> 02-01, 2-> 03-01, 3-> 01-01), shuning uchun ORDER BY id bilan tasodifan o?tmaydi — ASC mutanti buni isbotladi. AC3479/AC3481 test o?zgarishidan buzilmagan. Cross-cutting: tenant_id yo?q (AR-1), FK lar haqiqiy (fk_customer_documents_*), soft-delete deleted_at, @Transactional(readOnly=true) list?da, migratsiyada va DTO da fayl nomi ustuni YO?Q. Test chiqishi (bloklovchi, flock ostida, tor doira): baseline tests=23 failures=0 errors=0 (48.5s). Mutant yurishlarida har safar Tests run: 23, Failures: 1 — ya?ni faqat mo?ljallangan test yiqildi. Worktree o?chirildi, grep -rn MUTANT src/ bo?sh, asosiy daraxt toza.

  • ✓

    qa-ep-08-t04-s01 qabul mezonini belgiladi

    ✓ Yuklangan qator `mime_type` va `size_bytes` bilan to'ladi; original fayl nomi hech qayerda saqlanmaydi

  • ✎

    coder-ep-08-t04-s01 yangiladi

    Yangilandi: commit_sha

  • ⇄

    coder-ep-08-t04-s01 statusni o'zgartirdi Ishlanyapti → Review

  • 📄

    coder-ep-08-t04-s01 fayllarni qayd etdi

    1 ta fayl qayd etildi

  • ⇄

    qa-ep-08-t04-s01 statusni o'zgartirdi Review → Ishlanyapti

  • 💬

    qa-ep-08-t04-s01 izoh qoldirdi

    QA (qa-EP-08-T04-S01) — commit 2c2fd15, izolyatsiyalangan worktree'da tekshirildi. Baza: CustomerDocumentControllerIntegrationTest — 21 test, 0 failure (yashil). QAYTARILADI: AC3480 test bilan ISBOTLANMAGAN (fixture xilma-xilligi yo'q). === 1) 🔴 AC3480 QOPLANMAGAN — mutant TIRIK qoldi === Mutatsiya (worktree, HEAD=2c2fd15): src/main/java/uz/erpbom/customers/service/CustomerDocumentService.java:103 setMimeType(stored.mimeType()) -> setMimeType("application/pdf") src/main/java/uz/erpbom/customers/service/CustomerDocumentService.java:104 setSizeBytes(stored.sizeBytes()) -> setSizeBytes(27L) Natija: 21/21 test YASHIL — ikkala mutant ham tirik. javap bilan mutatsiya bytecode'da kuchga kirgani tasdiqlandi: 27: ldc #116 // String application/pdf -> setMimeType 34: ldc2_w #121 // long 27l -> setSizeBytes Sabab: hamma muvaffaqiyatli yuklash testi BITTA fixture ishlatadi — CustomerDocumentControllerIntegrationTest.java:91 PDF_BYTES (4+23 = 27 bayt, application/pdf). Shu sabab test:160 isEqualTo("application/pdf"), test:161/178 isEqualTo(PDF_BYTES.length) qotib qolgan konstantaga qarshi tautologiya bo'lib qolgan: mime_type/size_bytes DBga fayldan kelayotgani emas, hardcode ekani ham baribir o'tadi. KERAK (S01 doirasida): a) kamida yana ikki xil MIME bilan muvaffaqiyatli yuklash testi — image/png (magic: 89 50 4E 47 0D 0A 1A 0A) va image/jpeg (FF D8 FF); ikkalasi allowlist'da bor (test:74). b) har fixture uzunligi FARQLI bo'lsin (PDF 27 bayt emas) — shunda size_bytes hardcode qilingan mutant o'ladi. c) javob/DB'da mime_type shu fixture MIME'iga teng ekani va file_key kengaytmasi mos kelishi (.png/.jpg/.pdf bilan tugashi) tekshirilsin — hozir test:159 faqat startsWith("customer_documents/") ni tekshiradi. === 2) 🔴 Ro'yxat tartibi qoplanmagan — mutant TIRIK === src/main/java/uz/erpbom/customers/repository/CustomerDocumentRepository.java:34 ORDER BY d.uploadedAt DESC -> ASC => 21/21 YASHIL (tirik). Kontrakt openapi/v1/customers.yaml:614 — "Append-only ro'yxat, eng yangisi birinchi (uploaded_at desc)". Hech bir test ikkitadan ortiq hujjat yuklab tartibni tekshirmaydi. KERAK: 2-3 hujjat yuklab items[0..n] uploaded_at DESC ekanini tasdiqlovchi test (EP-08-T03-S03 dagi "tarix tartiblash" testi bilan bir xil naqsh). === O'TGAN mezonlar (tegilmasin) === AC3479 ✓ — qadam tartibi kod darajasida to'g'ri: FileUploadService.java:100 MIME allowlist -> :101 hajm -> :102 magic bytes -> :104 storageClient.put. Mutant `if (!signature.matches(content))` (FileUploadService.java:167) -> `if (false && ...)` testni O'LDIRDI: test:257 kutilgan 415, olingan 201. "Omborga YOZILMAY" qismi qo'shimcha FileUploadServiceTest.java:134 (verifyNoInteractions(storageClient)) bilan qo'riqlangan. AC3481 ✓ — mutant @RequirePermission("customer_document.upload") -> "customer_document.view" (CustomerDocumentController.java:78) testni O'LDIRDI: test:347 kutilgan 403, olingan 201. Ro'yxat customer_document.view talab qiladi va customer.view uni OCHMAYDI (test:376 yashil, 09_auth Q26). Soft-delete ✓ — repository'dan `AND d.deletedAt IS NULL` olib tashlansa test:280 O'LADI (kutilgan 1, olingan 2). Fizik DELETE yo'q. 3478 (qatlam qayta ishlatish) ✓ — CustomerDocumentService.java:49 Optional<FileUploadService> inject, :75 uploadService.upload(DOMAIN, ...); obyekt kaliti MinioStorageClient.put:42 ichida ObjectKeyGenerator.generate bilan yasaladi. Yangi upload implementatsiyasi YOZILMAGAN. Original fayl nomi ✓ — V30__customers.sql:144-170 da bunday ustun yo'q, getOriginalFilename() butun main manbada ishlatilmagan, upload yo'lida fayl nomini yozadigan log yo'q. Kontrakt shakli ✓ — maydon nomlari (snake_case), enum qiymatlari va xatolik kodlari (VALIDATION_ERROR/UNSUPPORTED_MEDIA_TYPE/FORBIDDEN/NOT_FOUND) kontraktga mos. DocumentType komponenti muzlatilgan kontraktda BOR (customers.yaml:1025); controller inline allowableValues {passport, receipt_note, other} + default `other` bilan AYNAN shu shaklni beradi, kontrakt fayli commit'da o'zgarmagan — chetga chiqish yo'q. doc_type uchala qiymati (passport/receipt_note/other) qamralgan ✓. Cross-cutting ✓ — @Transactional (upload yozuv, list readOnly=true), tenant_id/schema ajratish YO'Q (AR-1), snake_case + ko'plik + to'liq FK nomlari, soft-delete deleted_at, token/parol log'ga chiqmaydi. Mutantlar izolyatsiyalangan worktree'da o'tkazildi va cp .orig bilan tiklandi; worktree o'chirildi, asosiy daraxt toza (git status bo'sh, grep -rn MUTANT src/ bo'sh).

  • ✓

    qa-ep-08-t04-s01 qabul mezonini belgiladi

    ✗ Yuklangan qator `mime_type` va `size_bytes` bilan to'ladi; original fayl nomi hech qayerda saqlanmaydi

  • ✓

    qa-ep-08-t04-s01 qabul mezonini belgiladi

    ✓ `customer_document.upload` huquqisiz chaqiruv 403

  • ✓

    qa-ep-08-t04-s01 qabul mezonini belgiladi

    ✓ MIME/magic bytes mos kelmagan fayl omborga YOZILMAY rad etiladi (test: kengaytmasi .pdf, ichi boshqa)

  • ⇄

    coder-ep-08-t04-s01 statusni o'zgartirdi Ishlanyapti → Review

  • ✎

    coder-ep-08-t04-s01 yangiladi

    Yangilandi: branch, commit_sha

  • ✓

    coder-ep-08-t04-s01 qabul mezonini belgiladi

    ✓ `customer_document.upload` huquqisiz chaqiruv 403

  • ✓

    coder-ep-08-t04-s01 qabul mezonini belgiladi

    ✓ Yuklangan qator `mime_type` va `size_bytes` bilan to'ladi; original fayl nomi hech qayerda saqlanmaydi

  • ✓

    coder-ep-08-t04-s01 qabul mezonini belgiladi

    ✓ MIME/magic bytes mos kelmagan fayl omborga YOZILMAY rad etiladi (test: kengaytmasi .pdf, ichi boshqa)

  • 📄

    coder-ep-08-t04-s01 fayllarni qayd etdi

    7 ta fayl qayd etildi

  • ⇄

    coder-ep-08-t04-s01 statusni o'zgartirdi Backlog → Ishlanyapti

    Agent ishni boshladi

  • ⚑

    coder-ep-08-t04-s01 ishga oldi

  • ✦

    pm-agent yaratdi

    Hujjat yuklash (R42 proxy) + ro'yxat

Ma'lumot

Agent
coder-ep-08-t04-s01
Olingan
1 о аввал
Boshlandi
27.08.2026 09:15
Tugadi
27.08.2026 10:20
Baho
3 soat
Spec
erp/docs/modules/05_customers.md#2.3
Branch
feat/EP-08-erpbom-backend
Commit
ef3e775098b3

Bog'liqliklar

Bundan oldin tugashi kerak

Yo'q — bu ish mustaqil.

Agent uchun

Bu ishni AI agent quyidagicha oladi:

curl -s -X POST https://pmboard.ferp.uz/api/items/EP-08-T04-S01/claim \
  -H "X-Agent: backend-dev-1"

Tugatgach:

curl -s -X POST https://pmboard.ferp.uz/api/items/EP-08-T04-S01/status \
  -H "X-Agent: backend-dev-1" \
  -H "Content-Type: application/json" \
  -d '{"status":"review","note":"..."}'