Skip to content

[REFACTOR-TAGIHAN-CONTROLLER-DEDUPLICATION] Refactoring Arsitektur Controller & Deduplikasi Alur Orkestrasi Single Billing (V2 & V3) ​

Modul: Single Billing | Tipe: Refactoring | Stage Saat Ini: PRODUCTION | Tanggal Dokumen: 2026-09-07

PRODUCTION RELEASED

Dokumen ini telah berada dalam tahap PRODUCTION. Perubahan logika backend, migrasi skema/konfigurasi, dan rilis v1.9.2 telah diterapkan secara penuh di lingkungan Production via MR !232.

LIFECYCLE GUIDE — UPDATE BERTAHAP:

  1. Buat file ini saat selesai development. Isi semua section kecuali Staging & Production.
    • Tanggal Dokumen (Header) & Riwayat Update Log: Gunakan tanggal hari ini (pembuatan dokumen).
    • Baris Development (Lifecycle): Gunakan tanggal & jam commit terakhir terkait di branch development.
  2. Update baris Staging saat naik ke UAT. Ubah "Stage Saat Ini" di header menjadi STAGING.
  3. Update baris Production saat naik ke Prod. Ubah "Stage Saat Ini" di header menjadi PRODUCTION.
  4. Update entry di README.md setiap kali status berubah. -->

1. Informasi Tugas & Referensi Bisnis ​

  • Task ID / Nomor Referensi: REFACTOR-TAGIHAN-CONTROLLER-DEDUPLICATION

  • Sumber Instruksi: Refactoring Arsitektur Single Billing & Deduplikasi Kode Controller

  • Dokumen Referensi / Lampiran: Single Billing V3 - Multi Satker.postman_collection.json

  • Task / Dependensi Terkait (Cross-Service): FEAT-SIMPONI-V3-ISOLATION

  • Modul Terkait: Single Billing

  • Service / Repository: single-billing-BE

  • PIC Pengembang: Hermansyah Efendi

  • Latar Belakang & Ringkasan Kebutuhan: Pasca penambahan integrasi Simponi V3 (FEAT-SIMPONI-V3-ISOLATION), repositori single-billing-BE mengalami lonjakan metrik code duplication pada SonarQube Quality Gate hingga melanggar batas ambang batas toleransi (terdeteksi lebih dari 3.300 baris kode redundan). Hal ini terjadi karena alur logika bisnis penerimaan tagihan, validasi integritas payload Joi, pengelompokan satker (PNBP, BLU, BUP), kalkulasi nominal, pemanggilan gateway eksternal (Inaportnet, Sinkarkes), serta pencatatan audit trail disalin ulang antar-versi V2 dan V3 pada tagihan_controller.js dan billing_controller.js. Kondisi ini memperbesar risiko divergent bug fixes, menurunkan maintainability score, dan memicu kegagalan pipeline SonarQube. Refactoring ini mengekstraksi seluruh alur orkestrasi ke dalam helper terisolasi (tagihan_helper.js dan billing_helper.js), mengisolasi controller V3 ke folder dedicated app/controllers/v3/, mereduksi controller menjadi lightweight wrapper, dan menyatukan skema validasi Joi tanpa mengubah kontrak API eksisting (zero-regression).

  • Ruang Lingkup & Rincian Sub-Pekerjaan (Technical Scope & Milestones):

    • [x] Ekstraksi orkestrasi rekap tagihan ke processRekapTagihanOrchestrator pada app/helpers/tagihan_helper.js (-2.772 baris pada tagihan_controller.js)
    • [x] Ekstraksi orkestrasi request ulang billing ke processRequestBillingOrchestrator pada app/helpers/billing_helper.js (-532 baris pada billing_controller.js)
    • [x] Isolasi controller V3 ke direktori modular app/controllers/v3/ (tagihan_controller.js dan billing_controller.js)
    • [x] Unifikasi skema validasi Joi pada app/models/tagihan_models.js (schemaHeaderItems, schemaDetailItemsCommon) guna mengeliminasi definisi aturan SQL injection guard yang berulang
    • [x] Eliminasi sub-fungsi duplikat (koleksi unique satker, pengelompokan data, penyiapan payload database, logging cetakan) ke helper murni
    • [x] Verifikasi regresi fungsional untuk memastikan integrasi V2 dan V3 tetap berjalan normal tanpa perubahan endpoint contract

2. Deployment Lifecycle ​

#EnvironmentTanggal & WaktuPICStatusCatatan
1Development2026-06-25 15:40Hermansyah EfendiDEPLOYEDBranch: development (Merged from refactor/tagihan-controller-duplication)
2Staging (UAT)2026-10-14 13:00Hermansyah Efendi / QADEPLOYEDRelease Candidate via MR Staging !229. Co-deployed: [FEAT-SIMPONI-V3-ISOLATION, TASK-SET-EXPIRED-BILLING-V3, FEAT-BILLING-REKAP-EXPIRED-DATE-PAYLOAD, REFACTOR-TAGIHAN-CONTROLLER-DEDUPLICATION, FIX-PAYMENT-WEBHOOK-RACE-CONDITION, FIX-TAGIHAN-PREVENT-PAID-INVOICE-REORDER, FEAT-REQUEST-LOGGER-POSTMAN, TEST-DRAGONFLY-VITEST-SUITE, FEAT-RUNTIME-ENV-VALIDATION, TASK-NON-BLOCKING-BILLING-DISPATCH-AND-RETRY-CONFIG]
3Production2026-10-14 20:06achmad fauziDEPLOYEDBranch: prod via MR !232 (Release v1.9.2). Co-deployed: [FEAT-SIMPONI-V3-ISOLATION, TASK-SET-EXPIRED-BILLING-V3, FEAT-BILLING-REKAP-EXPIRED-DATE-PAYLOAD, REFACTOR-TAGIHAN-CONTROLLER-DEDUPLICATION, FIX-PAYMENT-WEBHOOK-RACE-CONDITION, FIX-TAGIHAN-PREVENT-PAID-INVOICE-REORDER, FEAT-REQUEST-LOGGER-POSTMAN, TEST-DRAGONFLY-VITEST-SUITE, FEAT-RUNTIME-ENV-VALIDATION, TASK-NON-BLOCKING-BILLING-DISPATCH-AND-RETRY-CONFIG]

Riwayat Update Log ​

TanggalEnvironmentPerubahanPIC
2026-10-14ProductionStatus diupdate ke PRODUCTION (DEPLOYED, CLOSED), rilis Release v1.9.2 via MR !232Hermansyah Efendi
2026-09-07DevelopmentInisialisasi draft audit log refactoring controller deduplication (commit ceb304a)Hermansyah Efendi

3. Analisis Teknis & Rincian Perubahan ​

  • Alur Logika & Bisnis:

    1. Pola Controller Ringan (Thin Controller Pattern): Controller pada app/controllers/tagihan_controller.js, app/controllers/billing_controller.js, app/controllers/v3/tagihan_controller.js, dan app/controllers/v3/billing_controller.js direduksi secara masif menjadi entry point tipis. Controller hanya memanggil orchestrator helper terkait dengan menyuplai context (req, res, next, version) ('v2' atau 'v3').
    2. Sentralisasi Orkestrasi Rekap Tagihan (tagihan_helper.js): Seluruh alur orkestrasi penerimaan tagihan, validasi integritas payload, pemisahan variasi satker (PNBP, BLU, BUP, dan kombinasi multi-satker Simponi), kalkulasi total tarif/nominal, persistensi database ke tabel billing (t_billing dan relasinya), pemanggilan webhook/gateway eksternal (Inaportnet, Sinkarkes), serta pencatatan logging/tracking audit dipusatkan dalam processRekapTagihanOrchestrator. Parameter versi ('v2' vs 'v3') digunakan secara deklaratif untuk menentukan endpoint Simponi dan mapping detail elemen (16 elemen untuk V2, 19 elemen untuk V3).
    3. Sentralisasi Orkestrasi Request Ulang Billing (billing_helper.js): Logika query pengecekan status transaksi billing gantung/pending ke database dan eksekusi request ulang ke Simponi dikonsolidasikan ke dalam processRequestBillingOrchestrator.
    4. DRY Skema Validasi Joi (tagihan_models.js): Elemen array Joi yang berulang diekstraksi ke variabel bersama schemaHeaderItems dan schemaDetailItemsCommon. Custom validator joiSqlTest untuk mitigasi SQL injection pattern tidak lagi didefinisikan ganda pada masing-masing versi. Elemen pembeda spesifik V3 (indeks 16–18) ditambahkan secara deklaratif.
    5. Net Code Reduction & Anti Divergent Bug Fixes: Pengurangan bersih kode sebanyak 1.792 baris kode (+1.566 baris penambahan helper terstruktur, -3.358 baris pembersihan kode duplikat). Refactoring ini mengeliminasi risiko perbaikan bug yang tidak sinkron (divergent bug fixes) antara jalur V2 dan V3.
  • Perubahan Database (DDL / DML):

    sql
    -- Tidak ada migration file yang terdeteksi. Murni refactoring arsitektur kode backend.
  • Kontrak API & Response Payload:Tidak ada penambahan atau perubahan kontrak API. Seluruh kontrak payload, routing, status code, dan response format untuk endpoint berikut dipertahankan secara identik (zero-regression):

    • POST /api/v2/terima-rekap-tagihan
    • POST /api/v3/terima-rekap-tagihan
    • POST /api/v2/request_ulang_billing
    • POST /api/v3/request_ulang_billing

4. Bukti Teknis (Technical Proof & Audit Trail) ​

  • Repository: single-billing-BE
  • Branch Utama: development (Merged from refactor/tagihan-controller-duplication)
  • Merge Request / PR: !232 (Release v1.9.2 — Merged to prod) | Staging: !229

Daftar Commit Terkait (Multi-Commit Trail) ​

Commit IDBranchAuthorTanggal & JamRingkasan Perubahan
f81d793refactor/tagihan-controller-duplicationHermansyah Efendi2026-06-25 13:55refactor(tagihan): resolve code duplication in rekap tagihan logic
313b84arefactor/tagihan-controller-duplicationHermansyah Efendi2026-06-25 15:03refactor(billing): resolve code duplication in request billing logic
a494f8brefactor/tagihan-controller-duplicationHermansyah Efendi2026-06-25 15:21refactor(tagihan): resolve code duplication in validation schemas
ceb304arefactor/tagihan-controller-duplicationHermansyah Efendi2026-06-25 15:40refactor(tagihan): resolve code duplication in tagihan orchestrator

Cuplikan Kode / Implementasi Inti ​

javascript
// app/controllers/v3/tagihan_controller.js (Controller menjadi sangat ringkas)
import { processRekapTagihanOrchestrator } from "../../helpers/tagihan_helper";

const rekapTagihanINSW_V3 = async (req, res, next) => {
  return processRekapTagihanOrchestrator(req, res, next, 'v3');
};

export { rekapTagihanINSW_V3 };
javascript
// app/models/tagihan_models.js (Unifikasi skema validasi Joi)
const schemaHeaderItems = [
  Joi.string().custom(joiSqlTest, 'Input mengandung SQL Injection pattern').required(),
  Joi.string().custom(joiSqlTest, 'Input mengandung SQL Injection pattern').allow("").required(),          
  Joi.string().custom(joiSqlTest, 'Input mengandung SQL Injection pattern').allow("").required(),
  Joi.string().regex(/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/).required(), // Date format
  Joi.string().custom(joiSqlTest, 'Input mengandung SQL Injection pattern').required(),
  Joi.string().custom(joiSqlTest, 'Input mengandung SQL Injection pattern').required(),
  Joi.string().custom(joiSqlTest, 'Input mengandung SQL Injection pattern').required(),
  Joi.string().custom(joiSqlTest, 'Input mengandung SQL Injection pattern').required(),
  Joi.string().custom(joiSqlTest, 'Input mengandung SQL Injection pattern').required(),
  Joi.number().required(),
  Joi.string().custom(joiSqlTest, 'Input mengandung SQL Injection pattern').required(),
  Joi.string().custom(joiSqlTest, 'Input mengandung SQL Injection pattern').required()
];

const schemaDetailItemsCommon = [
  Joi.string().custom(joiSqlTest, 'Input mengandung SQL Injection pattern').allow("").required(),
  Joi.string().custom(joiSqlTest, 'Input mengandung SQL Injection pattern').required(),
  Joi.string().regex(/^\d{4}-\d{2}-\d{2}$/).required(), // Date format
  // ... elemen umum di-share antar V2 dan V3
];

5. Bukti Verifikasi Pengujian (QA / Unit Test / API Verification) ​

A. Verifikasi Unit Test (Development Stage) ​

  • Test Suite File: tests/helpers/billing_helper.test.js, tests/helpers/tagihan_helper.test.js
  • Status Eksekusi CLI: PASSED
javascript
// tests/helpers/tagihan_helper.test.js
describe("processRekapTagihanOrchestrator", () => {
  it("should process v2 rekap tagihan successfully", async () => {
    // Verifikasi eksekusi delegasi orchestrator pada mode v2
  });
  it("should process v3 rekap tagihan successfully", async () => {
    // Verifikasi eksekusi delegasi orchestrator pada mode v3
  });
});
text
 RUN  v4.1.11 D:/WORK/LNSW/single-billing-BE
 ✓ tests/helpers/billing_helper.test.js (7 tests) 19ms
 ✓ tests/helpers/tagihan_helper.test.js (13 tests) 26ms
 Test Files  2 passed (2)
      Tests  20 passed (20)
   Start at  11:46:11
   Duration  451ms (transform 200ms, setup 125ms, import 202ms, tests 44ms, environment 1ms)

B. Panduan Pengujian QA & Verifikasi Staging (QA Playbook) ​

Disesuaikan dan sejalan dengan Postman Collection: Single Billing V3 - Multi Satker.postman_collection.json pada task FEAT-SIMPONI-V3-ISOLATION.PRINSIP QA: Live Gateway Simponi (Tanpa Mock) & Zero-Regression Dual Alur (V2 + V3). Pengujian difokuskan untuk membuktikan bahwa deduplikasi kode (ekstraksi orkestrator helper dan unifikasi skema Joi guna memenuhi SonarQube Quality Gate) tidak menimbulkan degradasi atau perubahan perilaku pada alur produksi eksisting.

  • Cakupan / Surface Pengujian: API / Postman Only (Direct Single Billing API & Live Gateway Simponi Sandbox)
  • Kebutuhan Akses / Role Akun: Token Bearer valid (), Postman Environment Dev/Staging dengan koneksi live ke Simponi Kemenkeu (MOCK_MODE=off).
  • Hasil Pengujian UAT: PASSED
  • Catatan QA: Verifikasi deduplikasi controller dan zero-regression dual flow (V2 dan V3) berhasil lolos pengujian UAT.
Skenario Pengujian QA (Test Scenarios) ​
Bagian I: Verifikasi Regresi Alur V2 Legacy (Backward Compatibility) ​
  1. Skenario 1 — Regression Test: Terima Rekap Tagihan V2 (16 Elemen Detail):

    • Postman Request: POST /api/v2/terima-rekap-tagihan
    • Pre-kondisi: Environment DEV/Staging aktif, payload V2 standar (detail 16 elemen, single satker PNBP).
    • Trigger / Request: Kirim payload rekap tagihan V2 ke entry-point controller tipis rekapTagihanINSW.
    • Ekspektasi Response: HTTP 200 OK, processRekapTagihanOrchestrator dengan mode 'v2' berhasil mengeksekusi mapping detail, kalkulasi tarif, serta penerbitan billing Simponi V2 tanpa deviasi logika.
    • Verifikasi Database / Log: Data tersimpan pada tabel t_billing dan terdisposisi ke Inaportnet / Sinkarkes secara normal.
  2. Skenario 2 — Regression Test: Request Ulang Billing V2:

    • Postman Request: POST /api/v2/request_ulang_billing
    • Pre-kondisi: Terdapat transaksi billing V2 dengan status pending di database.
    • Trigger / Request: Kirim request dengan parameter trx_id_insw.
    • Ekspektasi Response: HTTP 200 OK, processRequestBillingOrchestrator berhasil memproses request ulang ke Simponi V2.
    • Verifikasi Database / Log: Kolom status dan nomor billing ter-update sesuai respon Simponi V2.
Bagian II: Verifikasi Alur V3 Multi-Satker & Gateway Simponi (Sejalan dengan FEAT-SIMPONI-V3-ISOLATION) ​
  1. Skenario 3 — Happy Path: Agregasi Multi-Satker Ekstrem (7 Satker Hubla Lintas Wilayah):

    • Postman Request: Uji Multisatker - Tagihan Kemenhub 1
    • Pre-kondisi: Environment DEV/Staging terhubung langsung ke Live Gateway Simponi Sandbox (MOCK_MODE=off), Token Bearer valid.
    • Trigger / Request: POST /api/pengangkut/tagihan (atau /api/v3/terima-rekap-tagihan) membawa bundle 7 tagihan dari 7 Satker Hubla (KSOP & Disnav: Palembang, Pangkal Balam, Banjarmasin, Tanjung Emas, Teluk Palu, Ujung Pandang, Tanjung Priok).
    • Ekspektasi Response: HTTP 200 OK, code: "00" dari Gateway Simponi, mengembalikan kode billing konsolidasi (820xxxxxxx).
    • Verifikasi Database / Log: Seluruh 7 data tagihan tersimpan dengan asosiasi kode satker riil masing-masing dan status disposisi billing aktif.
  2. Skenario 4 — Happy Path: Baseline Single Satker (1 Satker Tunggal):

    • Postman Request: Uji Multisatker - Tagihan Kemenhub 2 & Uji Multisatker - Tagihan Kemenhub 4
    • Pre-kondisi: Live Gateway Simponi Sandbox aktif, Token Bearer valid.
    • Trigger / Request: POST /api/pengangkut/tagihan membawa tagihan 1 Satker (Disnav Samarinda 287260 atau KSOP Samarinda 287211).
    • Ekspektasi Response: HTTP 200 OK, code: "00". Membuktikan alur V3 tetap kompatibel saat menangani tagihan satker tunggal.
  3. Skenario 5 — Happy Path: Agregasi Multi-Satker Moderat (Kombinasi 2 Satker Berbeda):

    • Postman Request: Uji Multisatker - Tagihan Kemenhub 3
    • Pre-kondisi: Live Gateway Simponi Sandbox aktif, Token Bearer valid.
    • Trigger / Request: POST /api/pengangkut/tagihan menggabungkan tagihan Disnav Samarinda (287260) dan KSOP Samarinda (287211).
    • Ekspektasi Response: HTTP 200 OK, code: "00", kode billing konsolidasi berhasil diterbitkan.
  4. Skenario 6 — Happy Path: Agregasi Multi-Satker Kompleks (9 Tagihan Lintas 7 Satker Hubla):

    • Postman Request: Uji Multisatker - Tagihan Kemenhub 5
    • Pre-kondisi: Live Gateway Simponi Sandbox aktif, Token Bearer valid.
    • Trigger / Request: POST /api/pengangkut/tagihan membawa 9 tagihan lintas 7 Satker Hubla (KSOP Kuala Tungkal, Disnav Semarang, KSOP Tanjung Emas, Disnav Palembang, KSOP Palembang, Disnav Samarinda, KSOP Balikpapan).
    • Ekspektasi Response: HTTP 200 OK, code: "00", gateway Simponi menerima dan memproses seluruh array detail 19 elemen dari 9 tagihan tersebut.
  5. Skenario 7 — Negative Tests: Validasi Skema Joi Terpadu (Unifikasi Schema):

    • Postman Request:
      • Uji Multisatker - Tagihan Kemenhub (Minus)
      • Uji Multisatker - Tagihan Kemenhub (Satker Alhpanumeric - Header)
      • Uji Multisatker - Tagihan Kemenhub (Satker Alhpanumeric - Header Detail)
      • Uji Multisatker - Tagihan Kemenhub (Nominal Tidak Sesuai Detail)
    • Pre-kondisi: Skema validasi terpadu pada tagihan_models.js aktif.
    • Trigger / Request: Kirim payload dengan kondisi: nominal negatif, karakter non-numerik pada satker/akun, atau mismatch total nominal header vs akumulasi detail.
    • Ekspektasi Response: HTTP 400 Bad Request, validasi Joi menolak request sebelum diteruskan ke Simponi, membuktikan aturan validasi bersama tidak bocor pasca refactoring.
  6. Skenario 8 — Integration: Penanganan Error Respon Gateway Simponi Riil:

    • Pre-kondisi: Live Gateway Simponi Sandbox aktif, dikirimkan request dengan relasi satker/akun tidak valid.
    • Trigger / Request: POST /api/v3/terima-rekap-tagihan
    • Ekspektasi Response: Gateway Simponi mengembalikan kode penolakan resmi (IX, IR, IM, IS), orchestrator meneruskan format response error secara terstruktur tanpa uncaught exception.
  7. Skenario 9 — Regression Test: Request Ulang Billing V3:

    • Postman Request: POST /api/v3/request_ulang_billing
    • Pre-kondisi: Terdapat transaksi billing V3 pending / gantung di database.
    • Trigger / Request: Kirim request dengan parameter trx_id_insw.
    • Ekspektasi Response: HTTP 200 OK, processRequestBillingOrchestrator mengeksekusi request ulang ke Simponi V3 dan memperbarui record database.
  8. Skenario 10 — Integration: Pelunasan Pembayaran Billing DJA (activeinquiry_v2):

    • Postman Request: Uji Multisatker - Kirim Payment
    • Pre-kondisi: Kode billing aktif terbentuk di Single Billing dan terdaftar di Simponi.
    • Trigger / Request: POST /single-billing/dja/activeinquiry_v2 membawa payload pelunasan DJA (nomor billing dan NTPN).
    • Ekspektasi Response: HTTP 200 OK, status pembayaran billing berhasil diperbarui menjadi lunas (fl_paid = true).
Bukti Response Verifikasi Staging (Diisi saat UAT) ​
json
{
  "status": "PASSED",
  "note": "Pengujian verifikasi UAT dan validasi integrasi berhasil lolos, rilis production v1.9.2 telah live."
}

Single Source of Truth (SSOT) Arsitektur & Perubahan Teknis Backend