๐Ÿ“‹

MR Review Board

ide-phoenix ยท setelah tag 1.14.7

7 MR sudah merged ke main โ€” belum naik production. Validasi sebelum tagging.

Total MR 7
Sudah direview 7
Total issue ditemukan ~50
โš  CRITICAL/HIGH ada di !556, !557, !559, !563

Catatan: temuan ini dari pattern review otomatis โ€” beberapa mungkin false positive. Validasi manual tetap perlu sebelum tag production.

!556 โš  HIGH RISK โœ“ 10 issues 33 files ยท TRACING_ISSUE

feat: stabilize activation flow and optimize CPP Change Package handling

Refactor besar pada activation flow โ€” pisah CPP Change Package dari standard activation, guard antar job, completion service rewrite.

โ–ถ 10 Issues โ€” klik untuk lihat detail
๐Ÿ”ด CRITICAL 1. PostpaidChangePackageJob tidak idempotent โ€” double call ESB

File: app/jobs/postpaid_change_package_job.rb

Tidak ada guard return if postpaid_activation.waiting? di awal perform. Dengan sidekiq_options retry: 5, jika job crash setelah sukses call ESB tapi sebelum save_api_log selesai โ€” rescue memanggil failed!, override status :waiting jadi :failed. Retry berikutnya kirim request CPP kedua ke ESB untuk MSISDN yang sama.

๐Ÿ”ด CRITICAL 2. PostpaidActivationJob CPP guard โ€” activation stuck tanpa feedback

File: app/jobs/postpaid_activation_job.rb

Ketika order.cpp_type_change_package? true, hanya log error + return. Activation tetap di state awal (draft/pending) selamanya. User dan admin tidak tahu ada yang salah.

๐Ÿ”ด CRITICAL 3. OpenStruct di CheckCppStatusJob simulation โ€” silent nil data

File: app/jobs/check_cpp_status_job.rb

Simulated service memakai OpenStruct.new(...). Jika update_activation_success akses field yang tidak ada, return nil silently. Data nil tersimpan ke database tanpa error.

๐ŸŸ  HIGH 4. Hardcoded string Indonesian di all_activation action

File: app/controllers/customers/activations_controller.rb

flash[:alert] = "Aksi ini tidak berlaku untuk order ubah paket." โ€” hardcoded. Inconsistent dengan sync_change_package yang sudah pakai I18n.t().

๐ŸŸ  HIGH 5. rescue di PostpaidChangePackageJob override status tanpa cek konteks

File: app/jobs/postpaid_change_package_job.rb

Jika error di save_api_log (setelah activation sudah :waiting), rescue paksa set :failed. ESB sudah terima request, internal state salah. CheckCppStatusJob tidak poll activation yang :failed.

๐ŸŸ  HIGH 6. Potensi N+1 di view _postpaid_activations.html.erb

File: app/views/shared/orders/_postpaid_activations.html.erb

order.postpaid_activations.any? { |pa| pa.retry_reservation? } โ€” iterasi Ruby di view, trigger N+1 jika tidak ada eager-load yang sesuai.

๐ŸŸก MEDIUM 7. already_activated โ€” dead variable, intent tidak jelas

File: app/services/activations/completion_service.rb

Variable di-set tapi tidak pernah dipakai sebagai guard. check_and_complete_order selalu dipanggil meski already_activated = true.

๐ŸŸก MEDIUM 8. Hilangnya .with_msisdn scope di PostpaidActivationJob

File: app/jobs/postpaid_activation_job.rb

Diubah dari PostpaidActivation.with_msisdn.find(...) ke PostpaidActivation.find(...). Akses msisdn_number lazy load โ€” extra query per job execution.

๐ŸŸก MEDIUM 9. Error recovery ChangePackageService kalau enqueue gagal di tengah

File: app/services/orders/change_package_service.rb

Activation di-update ke :pending via update_all sebelum loop enqueue. Jika enqueue gagal mid-loop (Redis down), sebagian activation stuck di :pending tanpa job. Tidak ada rollback.

๐ŸŸก MEDIUM 10. postpaid_activation_job_spec.rb dihapus seluruhnya

File: spec/jobs/postpaid_activation_job_spec.rb

47 baris test dihapus, tidak ada pengganti yang cover behavior lama.

!563 โš  MED-HIGH โœ“ 8 issues 8 files ยท PHB-3264-flagging

[PHB-3264] Add flagging for document uploaded in previous order

Penandaan dokumen dari order sebelumnya โ€” fitur inheritance dokumen lintas order untuk customer yang sama.

โ–ถ 6 Issues โ€” klik untuk lihat detail
๐Ÿ”ด CRITICAL 1. Authorization terlalu luas โ€” sales bisa akses dokumen order lain

File: app/policies/order_policy.rb

Method user_is_sales_for_customer? kasih akses secured_document jika user adalah sales untuk ANY order milik customer X. Sales rep order A bisa lihat dokumen order B (different sales, same customer). Violates least-privilege & order boundary security.

Fix: tambah cek apakah user adalah sales_id untuk THIS order spesifik, atau whitelist hanya inheritable documents.

๐ŸŸ  HIGH 2. State leak: customer.orders tanpa explicit customer_id check

File: app/models/order.rb

Query pakai customer.orders โ€” bergantung pada order.customer association yg bisa nil/stale. Multi-tenant scenario bisa expose order milik customer lain.

Fix: pakai Order.where(customer_id: self.customer_id) eksplisit + guard nil.

๐ŸŸ  HIGH 3. Active Storage join syntax โ€” perlu verifikasi runtime

File: app/models/order.rb

Pakai .joins("#{document_type}_attachment".to_sym) untuk dynamic Active Storage join. Walaupun Rails has_one_attached generate association akta_attachment, dynamic symbol generation rawan typo dan tidak validate document_type. Jika document_type bukan dari whitelist โ†’ bisa raise atau return wrong.

Fix: validasi document_type vs DocumentApproval::DOCUMENT_TYPES dulu sebelum dynamic join.

๐ŸŸก MEDIUM 4. Silent nil saat document_type invalid

File: app/models/order.rb

Tidak ada validasi document_type dari DocumentApproval::DOCUMENT_TYPES. Invalid type silent return nil โ€” sembunyikan bug dev/integration.

๐ŸŸก MEDIUM 5. Kontradiksi logika fpn โ€” non-inheritable tapi required

File: app/models/order.rb

fpn masuk NON_INHERITABLE_DOCUMENTS tapi requires_fpn_document? = true untuk add_member orders. Kalau add_member memang butuh inheritance fpn, ini contradicting business logic.

๐Ÿ”ด CRITICAL 6. View button previous order pakai rails_blob_path โ€” bypass authorization

File: app/views/shared/_document_approval_list.html.erb

Link View untuk dokumen dari previous order pakai rails_blob_path(prev_order.send(document_type), ...) โ€” ini URL signed time-limited ke blob langsung, tanpa cek secured_document? policy. Siapa saja yang punya URL bisa akses dokumen KYC sensitif tanpa authentikasi. Beda dengan View button current order yang lewat sales_document_preview_page_portal_sales_order_path (controller + policy check).

Fix: pakai portal_secured_document_path(prev_order, document_type: document_type) atau endpoint custom yang verify authorization sebelum serve blob.

๐ŸŸ  HIGH 7. NPWP name/address mismatch antara dokumen prev order dan data current customer

File: app/views/shared/_document_approval_list.html.erb

Ketika document_type == 'npwp' dan ada prev_order dengan NPWP, view menampilkan: (1) dokumen PDF dari prev_order โ€” mungkin punya nama/alamat lama, tapi (2) NPWP name/address inline edit di bawah tetap tampil dari customer.npwp_name dan customer.npwp_address (data current). Jika data NPWP customer sudah berubah sejak order lama, verificator lihat PDF lama tapi inline data berbeda โ€” bisa approve berdasarkan data yang salah.

Fix: saat dokumen dari prev_order, tampilkan NPWP name/address dari prev_order.customer (snapshot lama), atau sembunyikan inline edit karena dokumen yang dipakai adalah dari order sebelumnya.

๐ŸŸข LOW 8. Test memoization terlalu lemah

File: spec/models/order_spec.rb

Test pakai .where.twice mock tanpa verify actual query count reduce. Cache rusak, test masih hijau.

Fix: pakai ActiveRecord::QueryRecorder untuk count real DB queries.

!559 โš  HIGH RISK โœ“ 5 issues 2 files ยท PHB-3260-siebel-sync

[PHB-3260] feat(siebel): ensure complete document sync for active orders

Ubah query filter dokumen yang sync ke Siebel SFTP โ€” termasuk skipped/non-approved untuk active orders.

โ–ถ 5 Issues โ€” klik untuk lihat detail
๐Ÿ”ด CRITICAL 1. Query where.not(status: :skipped) include rejected ke Siebel

File: app/services/siebel_sftp_uploader_service.rb

Query lama: where(status: :approved). Query baru: where.not(status: :skipped). Match: pending(0), approved(1), rejected(2). Rejected docs sekarang ikut sync ke Siebel CRM โ€” itu dokumen yang gagal verifikasi, harusnya tidak pernah masuk ke CRM. Data integrity hancur.

Fix: pakai positive filter where(status: [:approved]) atau eksplisit exclude rejected: where(status: :approved).where.not(status: :skipped).

๐Ÿ”ด CRITICAL 2. Status :delivery dihapus dari filter โ€” tapi spec masih cek :delivery excluded

File: app/services/siebel_sftp_uploader_service.rb + spec

Diff hapus Order.statuses[:delivery] dari array. Tapi spec baru tetap test ekspektasi :delivery orders TIDAK upload. Mismatch antara intent code dan spec โ†’ kemungkinan bug regression atau salah satu salah.

Fix: tentukan dulu apakah :delivery harus sync atau tidak, sinkronkan code & spec.

๐ŸŸ  HIGH 3. Spec eksplisit ekspektasi rejected docs ter-upload ke Siebel

File: spec/services/siebel_sftp_uploader_service_spec.rb

Test "uploads approved and rejected documents but skips skipped ones" eksplisit ekspektasi rejected_document_approval ter-upload. Spec validasi behavior yang salah dari business perspective.

๐ŸŸก MEDIUM 4. Race condition di mark_documents_as_uploaded

File: app/services/siebel_sftp_uploader_service.rb

CSV ditulis dulu, mark_documents_as_uploaded baru dipanggil end-of-batch via update_all. Jika service interrupt mid-flow (OOM, SIGTERM, timeout), file di SFTP sudah ada tapi flag upload_siebel_sftp_at belum di-set. Run berikutnya re-upload duplicate.

Fix: mark per-document segera setelah upload sukses, bukan batch end.

๐ŸŸก MEDIUM 5. Pagination offset += failed_count rawan loop infinite

File: app/services/siebel_sftp_uploader_service.rb

Jika satu batch gagal semua (Siebel down, SFTP timeout), offset hanya naik failed_count. Kalau ordering query change, possible reprocess same docs. ID-based pagination lebih aman.

!557 โš  MED-HIGH โœ“ 7 issues 16 files ยท enhancement/label-group-feature

Label group feature: delete group, sort enhancement, i18n

Fitur label group MSISDN โ€” delete, sorting, i18n. Touch dashboard customer + admin + JS controller.

โ–ถ 7 Issues โ€” klik untuk lihat detail
๐ŸŸ  HIGH 1. delete_group_label tanpa transaction wrapper

File: app/controllers/customers/dashboards_controller.rb

Pakai update_all langsung tanpa transaction. Kalau gagal di tengah (DB connection drop, server crash), state DB partial โ€” sebagian MSISDN lost label, sebagian tetap.

Fix: ActiveRecord::Base.transaction { affected.update_all(...) }

๐ŸŸ  HIGH 2. JS confirmDeleteGroup tidak cek HTTP status sebelum parse JSON

File: app/javascript/controllers/msisdn_group_edit_controller.js

await res.json() dipanggil tanpa cek res.ok. Kalau server return 5xx dengan body HTML, parse error โ†’ unhandled promise rejection. User dapat alert kosong/aneh.

๐ŸŸ  HIGH 3. Role check mismatch di dashboard_helper

File: app/helpers/dashboard_helper.rb

dashboard_i18n_namespace cek has_role?(:customer), tapi controller authorize via has_role?(:user). Branch elsif tidak pernah ke-trigger โ€” fallback selalu dipake. Effectively dead branch + i18n namespace bisa salah.

๐ŸŸก MEDIUM 4. Hardcoded Indonesian fallback di JS controller

File: app/javascript/controllers/msisdn_group_edit_controller.js

Fallback string i18n (Menyimpan..., Gagal menyimpan, dst) hardcoded Indonesian. User English-locale dapat pesan Indonesia kalau data attr missing.

๐ŸŸก MEDIUM 5. Admin routes tidak punya delete_group_label endpoint

File: config/routes.rb

Customer dashboards punya endpoint :group_labels, :update_activation_group, :bulk_update_activation_group, :delete_group_label. Admin dashboards cuma :index, :usage. Inkonsistensi โ€” admin tidak bisa pakai fitur ini, padahal mungkin perlu untuk supervise.

๐ŸŸข LOW 6. Missing i18n key 'label' di locale files

File: app/views/shared/dashboards/_msisdn_group_block.html.erb

t("#{ns}.label") dipanggil tapi key 'label' tidak ada di admin/en.yml & customers/en.yml. Akan tampil "translation missing".

๐ŸŸข LOW 7. Sort comparator tidak coalesce undefined dataset

File: app/javascript/controllers/msisdn_sort_controller.js

Akses data-sort-msisdn, data-sort-type tanpa null-check. Row tanpa attribute โ†’ undefined comparison โ†’ unstable sort.

!558 โš  MEDIUM โœ“ 5 issues 8 files ยท platinum_retail-quota

[feat] Add usage dashboard and quota fields for platinum_retail product type

Tambah quota fields & dashboard untuk product_type platinum_retail. Touch product model, helper, view admin.

โ–ถ 5 Issues โ€” klik untuk lihat detail
๐ŸŸ  HIGH 1. quota_product? predicate tidak konsisten โ€” verifikasi manual

File: app/models/product.rb

Diff update quota_product? include platinum_retail. Tapi method serupa di model lain (mis: show_quota_member_limit?) dan helper masih cek shared_quota? || fixed_quota? manual. Inconsistency: field visibility config vs predicate vs view condition perlu di-grep ulang seluruhnya.

Action: grep -rn "shared_quota? || fixed_quota?" app/ dan pastikan semua sudah pakai quota_product?.

๐ŸŸก MEDIUM 2. View badge logic โ€” color mismatch untuk platinum_retail

File: app/views/customers/dashboards/index.html.erb + admin

Customer dashboard view masih ternary shared_quota? ? blue : purple, padahal MR ekspektasi platinum_retail = amber badge. Kalau view ini tidak diubah, badge salah.

๐ŸŸก MEDIUM 3. Quota fields section condition di admin show

File: app/views/admin/products/show.html.erb

Condition @product.shared_quota? || @product.fixed_quota? tidak include platinum_retail โ†’ admin form tidak render quota fields untuk platinum_retail. Helper config sudah include, tapi view block-nya.

๐ŸŸก MEDIUM 4. Data quota label โ€” per-MSISDN vs Pool

File: app/views/admin/products/show.html.erb

Cek hanya fixed_quota? untuk per-MSISDN label. platinum_retail tampil label "Pool" yang salah.

๐ŸŸข LOW 5. Scope rename shared_or_fixed_quota โ†’ quota_products belum konsisten

File: app/models/product.rb

Refactor scope ke nama baru tapi semua call site di-grep dulu. Kalau ada controller/view yang masih panggil scope lama โ†’ NoMethodError.

!555 โœ“ LOW RISK โœ“ 3 issues 7 files ยท PHB-3262-fix-manage-order

[PHB-3262] fix: manage order search, sort, filter, and sim card 500 error

Fix manage order search/sort/filter & 500 error sim card. Scope kecil, mostly bug fixes.

โ–ถ 3 Issues โ€” klik untuk lihat detail
๐ŸŸก MEDIUM 1. order() pakai string key โ€” inkonsisten dengan model lain

File: app/models/order.rb:736

orders.order(sort_column => safe_sort_direction) โ€” string key & string value. Rails Arel terima keduanya, tapi Lead.rb:186 dan Product.rb:283 pakai .to_sym. Inkonsistensi pattern, bukan bug langsung.

Note: agent original klaim ini HIGH; gue downgrade ke MEDIUM karena Rails accept string key di hash-form .order().

๐ŸŸก MEDIUM 2. Test sort cuma cek not_to raise_error

File: spec/models/order_spec.rb:191-203

Test "sorts asc/desc without raising" tidak verify hasil urutan beneran. Kalau sort silently broken, test tetap green. Sort test lain di file sama (line 2601+) sudah proper.

๐ŸŸข LOW 3. SQL injection check โ€” pastikan whitelist sort_column

File: app/models/order.rb

Sort column dari user input. Verify scope filter_and_sort punya allowlist column name (bukan whatever user kirim). Diff harus include validasi.

Action manual: cek implementation filter_and_sort punya SORTABLE_COLUMNS = %w[...].freeze + raise jika di luar allowlist.

!554 โš  MED-HIGH โœ“ 8 issues 32 files ยท PHB-3264-waive-fee

[PHB-3264] feat: adjust verification flow for fixed quota orders and returning customers (KYC)

Penyesuaian verification flow โ€” fixed quota orders, returning customers, skip document, waive activation fee.

โ–ถ 8 Issues โ€” klik untuk lihat detail
๐ŸŸ  HIGH 1. Race condition: skip_document! parallel call โ†’ double advance

File: app/models/document_approval.rb:111

Cek !order.payment_expired_at? tanpa DB lock. Dua call parallel bisa lewat cek yang sama, dua-duanya advance_order_to_payment!. Akibat: duplicate VerificatorMailer.approval_notification, duplicate push notif, audit log duplikat.

Fix: order.with_lock { ... } atau guard form_stage != :payment_stage.

๐ŸŸ  HIGH 2. Reload order tanpa refresh association document_approvals

File: app/models/document_approval.rb:101

Setelah update document_approval status :skipped + purge attachment, code order.reload + cek all_document_approved_and_optional_document_uploaded?. Reload tidak refresh in-memory association โ€” possibly stale data di method check.

Fix: pakai order.reload(includes: :document_approvals) atau pass updated state eksplisit.

๐ŸŸก MEDIUM 3. Safe-nav customer&.eligible_for_fast_track? bypass restriction

File: app/controllers/customers/verifications_controller.rb:89

@order.customer&.eligible_for_fast_track? โ€” kalau customer nil, condition false, redirect tidak terjadi. Returning customer object tanpa linked customer record bisa bypass fast-track restriction.

๐ŸŸก MEDIUM 4. State change order + approval tidak atomic (no transaction)

File: app/models/document_approval.rb:82

order.update! dan approval.update! dua DB call terpisah tanpa transaction. Kalau approval.update gagal validasi, order.waive_activation_fee sudah ke-set false โ†’ state inconsistent.

๐ŸŸก MEDIUM 5. skip_document! tanpa idempotency guard

File: app/models/document_approval.rb:66

Method bisa dipanggil dua kali (Sidekiq retry, network retry, double-click). Tidak ada cek return false if approval.skipped? di awal. Akibat: duplicate VerificatorMailer.optional_document_skipped email.

๐ŸŸก MEDIUM 6. returning_customer + fixed_quota โ†’ MoU validation gap

File: app/models/order.rb:593

all_required_documents_approved? return true untuk returning_customer? tanpa cek requires_mou?. requires_mou? = !returning_customer?, tapi fixed_quota_product? bisa override. Possible gap: fixed quota re-order considered approved tanpa MoU.

๐ŸŸก MEDIUM 7. Sales verification_stage_submit cek MoU tanpa reload

File: app/controllers/sales/verifications_controller.rb:38

@order.mou.attached? || !@order.requires_mou? tanpa reload. Customer upload MoU paralel + sales klik verify โ†’ state stale, valid submission ditolak.

๐ŸŸข LOW 8. Mailer error tanpa explicit handler di skip_document!

File: app/models/document_approval.rb:91

deliver_later tanpa rescue. Mailer config error โ†’ exception bubble ke generic rescue => e di controller. Mailer issues tertelan rescue umum, tidak mudah di-debug.

Dibuat oleh Semar ยท Punakawan AI ยท review.hanif.app ยท last updated