Skip to content

[FIX-RECEIVE-NOMOR-AJU-SITOLAUT-HANGING-AND-OBSERVABILITY] Eliminasi Hanging Request Endpoint receiveNomorAju, Safe Error Handling Axios SITOLAUT, dan Peningkatan Observability Log Grafana

Modul: SIPT/PAB | Tipe: Bugfix | Stage Saat Ini: DEVELOPMENT | Tanggal Dokumen: 2026-08-28


1. Informasi Tugas & Referensi Bisnis

  • Task ID / Nomor Referensi: FIX-RECEIVE-NOMOR-AJU-SITOLAUT-HANGING-AND-OBSERVABILITY

  • Sumber Instruksi: Investigasi Missing Access Log Grafana pada Endpoint /receiveNomorAju saat Downstream Error

  • Dokumen Referensi / Lampiran: Tidak ada

  • Task / Dependensi Terkait (Cross-Service):

  • Modul Terkait: SIPT/PAB

  • Service / Repository: sipt-backend

  • PIC Pengembang: Hermansyah Efendi

  • Ringkasan Non-Teknis (Executive Summary): Ketika koneksi ke pihak ketiga (SITOLAUT) terputus, sistem sebelumnya mengalami kegagalan penanganan error yang menyebabkan proses transaksi terhenti di tengah jalan tanpa mengirimkan jawaban akhir ke pengirim (request hanging). Karena transaksi tidak pernah selesai, sistem monitoring (Grafana) tidak sempat mencatat riwayat kedatangan data tersebut, sehingga transaksi terlihat "hilang" dari dashboard.

    Setelah dilakukan perbaikan:

    1. Sistem dibuat kebal terhadap gangguan koneksi pihak ketiga (tidak lagi macet/menggantung).
    2. Sistem selalu menyelesaikan transaksi dan memberikan status pasti kepada pengirim.
    3. Seluruh riwayat transaksi kini tercatat 100% di dashboard Grafana disertai label peringatan jika ada integrasi eksternal yang gagal.
  • Latar Belakang & Ringkasan Kebutuhan: Berdasarkan investigasi hilangnya jejak log HTTP access di Grafana maupun tabel sipt.logs pada endpoint POST /api/receiveNomorAju saat downstream service SITOLAUT mengalami kegagalan:

    1. Terjadi fatal crash runtime TypeError: Cannot read properties of undefined (reading 'data') pada blok catch fungsi sendSitolaut karena membaca langsung error.response.data pada error jaringan (AxiosError: ECONNREFUSED / timeout) yang tidak memiliki objek response.
    2. Pola callback nesting insertNomorAju(payload, async (result, err) => { ... }) dipanggil secara synchronous tanpa await. Ketika crash terjadi di dalam callback, Node.js menganggapnya sebagai Unhandled Promise Rejection, baris res.status(200).json(...) tidak pernah dieksekusi, koneksi HTTP menggantung (hanging socket), dan event res.on('finish') tidak pernah terpicu. Akibatnya, middleware pino-http dan incoming_request_log tidak pernah mencatat access log transaksi.
    3. Response kegagalan parsial yang mengembalikan HTTP 200 tercatat sebagai log level info (atau silent jika durasi eksekusi di bawah HTTP_SLOW_LOG_THRESHOLD_MS), sehingga query Grafana dengan filter level="error" tidak menangkap transaksi bermasalah tersebut.
    4. Format pesan pino-http disederhanakan dan diperkaya dengan log instan Incoming, Completed, dan Failed request beserta response time (ms) untuk memastikan pelacakan request masuk-keluar yang deterministik.
  • Ruang Lingkup & Rincian Sub-Pekerjaan (Technical Scope & Milestones):

    • [x] Milestone 1 — Root Cause Analysis: Identifikasi penyebab hilangnya log HTTP di pino-http akibat request hanging saat koneksi SITOLAUT ditolak (ECONNREFUSED).
    • [x] Milestone 2 — Safe Axios Error Handling (sendSitolaut): Implementasi safe extraction menggunakan optional chaining error.response?.data dengan fallback { message: error.message, code: error.code } agar sistem tidak crash saat server tujuan offline/timeout.
    • [x] Milestone 3 — Pure Async Refactoring (insertNomorAju): Mengubah signature fungsi dari callback ke pure promise async (payload) dengan semantic error throwing (NotFoundError).
    • [x] Milestone 4 — Pure Async Refactoring (receiveNomorAju): Mengubah alur controller menjadi sekuensial linier dengan await untuk menjamin siklus HTTP response selalu selesai tuntas.
    • [x] Milestone 5 — Observability & Warning Logging: Menambahkan logger.warn eksplisit pada kegagalan downstream agar terindeks jelas di dashboard monitoring Grafana.
    • [x] Milestone 6 — Enhanced Pino HTTP Logging: Menambahkan customReceivedMessage, customSuccessMessage (dengan response time), dan customErrorMessage (dengan response time & pesan error), serta menghapus customLogLevel berlebih untuk menjamin konsistensi log masuk-keluar.
    • [x] Milestone 7 — Safe Authorization Guard: Menambahkan pengamanan akses field scopeGranted pada middleware otorisasi.
    • [x] Milestone 8 — Empirical Test Suite Verification: Penambahan unit test skenario ECONNREFUSED, format logging, dan verifikasi 102 unit tests Vitest (100% pass).

2. Deployment Lifecycle

#EnvironmentTanggal & WaktuPICStatusCatatan
1Development2026-08-28 14:59Hermansyah EfendiDEPLOYEDBranch: development (Commit: 71816cda .. 26ac527e)
2Staging (UAT)PENDING
3ProductionPENDING

Riwayat Update Log

TanggalEnvironmentPerubahanPIC
2026-08-28DevelopmentInisialisasi draft audit log perbaikan hanging request, safe Axios error extraction, enhanced pino-http logs, dan QA playbookHermansyah Efendi

3. Analisis Teknis & Rincian Perubahan

  • Alur Logika & Bisnis:

    • Safe Error Extraction pada Integrasi SITOLAUT (app/models/newsend_sipt_models.js): Mengganti pembacaan JSON.stringify(error.response.data) yang memicu TypeError ketika error.response bernilai undefined (kondisi network socket error seperti ECONNREFUSED atau timeout) dengan ekstraksi defensif: error.response?.data ? ... : JSON.stringify({ message: error.message, code: error.code }). Payload error yang disimpan ke tabel sipt.logs kini selalu valid string tanpa risiko fatal exception.
    • Eliminasi Callback Nesting & Hanging Socket (app/controllers/newsend_sipt_controller.js & app/models/newsend_sipt_models.js): Mengubah signature insertNomorAju menjadi pure promise (async (payload)) dan memanggilnya secara linier menggunakan await insertNomorAju(payload) pada controller. Hal ini mengeliminasi unhandled promise rejection di dalam callback asynchronous, menjamin res.status(200).json(...) selalu dieksekusi, dan memastikan event res.on('finish') pada pino-http terpicu sehingga seluruh request tercatat di Grafana.
    • Enhanced HTTP Request Logging (app/middlewares/http-logger.js):
      • Menambahkan customReceivedMessage (--> Incoming: METHOD URL) pada detik pertama request masuk ke Express.
      • Menambahkan customSuccessMessage (<-- Completed: METHOD URL STATUS (TIMEms)) dan customErrorMessage (<-- Failed: METHOD URL STATUS (TIMEms) - ERROR).
      • Menghapus customLogLevel berlebih untuk memastikan konsistensi level logging transaksi.
    • Peningkatan Observability Kegagalan Parsial (app/controllers/newsend_sipt_controller.js): Menambahkan structured log warning logger.warn({ nomor_layanan: nomorLayanan, sitolautSuccess, pelindoSuccess }, message) pada kondisi di mana salah satu atau kedua downstream service gagal. Hal ini memungkinkan tim operasional memantau anomali integrasi via query Grafana tanpa tersamarkan oleh HTTP response status 200 OK.
    • Defensive Guard Middleware Otorisasi (app/middlewares/authorization.js): Menambahkan optional chaining dan validasi tipe typeof scopeGranted === 'string' sebelum memanggil .split(' ') untuk mencegah crash runtime saat memproses token tanpa atribut scope.
  • Perubahan Database (DDL / DML):

    sql
    -- Tidak ada perubahan skema database (DDL/DML) untuk task ini.
    -- Perubahan difokuskan pada level application logic, defensive error handling, refactoring async controller, pino-http logging, dan observability.
  • Kontrak API & Response Payload:

    POST /api/receiveNomorAju

    • Deskripsi: Menerima nomor aju pengajuan PAB dari INSW/KL, memperbarui tracking & nomor pengajuan, lalu meneruskan sinkronisasi ke SITOLAUT dan Pelindo.
    • Autentikasi / Guard: logReceiveNomorAju
    • Request Header:
      • Content-Type: application/json
    • Request Body:
      json
      {
        "header": {
          "no_aju": "000001/PAB/2026",
          "tgl_aju": "2026-08-28 10:00:00",
          "id_referensi": "PAB-20260828-0001",
          "url_dokumen": "https://storage.insw.go.id/dokumen/pab/0001.pdf"
        }
      }
    • Response Payload (200 OK — Sukses Penuh):
      json
      {
        "code": 200,
        "keterangan": "Data berhasil diterima"
      }
    • Response Payload (200 OK — Partial Downstream Failure):
      json
      {
        "code": 200,
        "keterangan": "Data berhasil diterima, namun gagal kirim sitolaut"
      }
    • Response Error (404 Not Found / 500 Internal Server Error):
      json
      {
        "code": 404,
        "keterangan": "Data pengajuan tidak ditemukan"
      }

4. Bukti Teknis (Technical Proof & Audit Trail)

  • Repository: sipt-backend
  • Branch Utama: development
  • Merge Request / PR: -

Daftar Commit Terkait (Multi-Commit Trail)

Commit IDBranchAuthorTanggal & JamRingkasan Perubahan
71816cda68815924680dff9a7a6f61453afa9c8ddevelopmentHermansyah Efendi2026-08-28 11:12fix(auth): add safe check for scopeGranted in authorization middleware
50ebe2e8d08b906a563a129eae09f77fa9fce47fdevelopmentHermansyah Efendi2026-08-28 11:12fix(sitolaut): prevent crash on network error and refactor receiveNomorAju to pure async
bfff3300809edf5f68052a5743ac533b0927b7cddevelopmentHermansyah Efendi2026-08-28 11:25refactor(logger): simplify pino-http configuration by removing redundant customLogLevel
193b0d7f6c7606fb94f728ffff9beaa333c560efdevelopmentHermansyah Efendi2026-08-28 11:26docs(changelog): update unreleased entries for sitolaut fix and pino-http request logs
8b6720cea76ef24124588172a99eef60e91f67bedevelopmentHermansyah Efendi2026-08-28 11:31chore(deps): fix npm audit vulnerabilities in package-lock.json
26ac527e54aa6d72c05681084bc3307cbb33a422developmentHermansyah Efendi2026-08-28 11:32docs(changelog): record dependency audit fix in unreleased entries

Cuplikan Kode / Implementasi Inti

javascript
// File: app/models/newsend_sipt_models.js (sendSitolaut catch block)
} catch (error) {
  await insertTracking(payload.no_layanan, statusSipt.gagal_sitolaut);
  const sitolautErr = {
    code: 500,
    status: false,
    err: "Gagal kirim sitolaut",
  };
  logger.error({ err: error, errorMessage: sitolautErr }, "sendSitolaut error");
  const errorPayload = error.response?.data
    ? (typeof error.response.data === "string" ? error.response.data : JSON.stringify(error.response.data))
    : JSON.stringify({ message: error.message, code: error.code });
  await insertLogs(
    payload.no_layanan,
    `${process.env.SITOLAUT_URL}`,
    errorPayload,
    JSON.stringify(payload),
  );
  return false;
}
javascript
// File: app/controllers/newsend_sipt_controller.js (receiveNomorAju pure async & structured warning log)
await insertNomorAju(payload);
let sitolautSuccess = null;
const isSitolautSubmission = checkExist[0]?.is_sitolaut === true;
if (isSitolautSubmission) {
  const { header } = JSON.parse(checkExist[0]?.payload);
  const payloadData = {
    id_referensi: header?.id_referensi || nomorLayanan,
    no_layanan: nomorLayanan,
    url: urlDokumen,
  };
  sitolautSuccess = await sendSitolaut(payloadData);
}
const pelindoRes = await sendPelindo(nomorLayanan);
let message = "Data berhasil diterima";
if (sitolautSuccess === false && pelindoRes.success === false) {
  message = "Data berhasil diterima, namun gagal kirim sitolaut dan pelindo";
  logger.warn({ nomor_layanan: nomorLayanan, sitolautSuccess, pelindoSuccess: pelindoRes.success }, message);
} else if (sitolautSuccess === true && pelindoRes.success === false) {
  message = "Data berhasil diterima, berhasil kirim sitolaut, namun gagal kirim pelindo";
  logger.warn({ nomor_layanan: nomorLayanan, sitolautSuccess, pelindoSuccess: pelindoRes.success }, message);
} else if (sitolautSuccess === false && pelindoRes.success === true) {
  message = "Data berhasil diterima, namun gagal kirim sitolaut";
  logger.warn({ nomor_layanan: nomorLayanan, sitolautSuccess, pelindoSuccess: pelindoRes.success }, message);
} else if (pelindoRes.success === false) {
  message = "Data berhasil diterima, namun gagal kirim pelindo";
  logger.warn({ nomor_layanan: nomorLayanan, sitolautSuccess, pelindoSuccess: pelindoRes.success }, message);
}
return res.status(200).json({ code: 200, keterangan: message });

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

A. Verifikasi Unit Test (Development Stage)

  • Test Suite Files:
    • tests/controllers/newsend_sipt_controller.test.js
    • tests/models/newsend_sipt_models.test.js
    • tests/middlewares/http-logger.test.js
    • tests/middlewares/authorization.test.js
    • tests/helpers/kemendag-axios-interceptor.test.js
  • Status Eksekusi CLI: PASSED (102/102 tests passed)
text
 RUN  v4.1.11 D:/WORK/LNSW/sipt-backend
 ✓ tests/middlewares/authorization.test.js (19 tests) 22ms
 ✓ tests/middlewares/http-logger.test.js (12 tests) 14ms
 ✓ tests/helpers/kemendag-axios-interceptor.test.js (10 tests) 17ms
 ✓ tests/models/newsend_sipt_models.test.js (29 tests) 28ms
 ✓ tests/controllers/newsend_sipt_controller.test.js (32 tests) 95ms
 Test Files  5 passed (5)
      Tests  102 passed (102)
   Start at  14:59:45
   Duration  896ms (transform 582ms, setup 0ms, import 1.23s, tests 176ms, environment 1ms)

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

  • Cakupan / Surface Pengujian: B2B Webhook + Data Synchronization Verification
  • Kebutuhan Akses / Role Akun: Public / Internal Endpoint (Tanpa API Key insw-key & Cookie)
  • Tujuan Pengujian:
    1. Memverifikasi pembuatan data baru dari SITOLAUT diteruskan ke Kemendag hingga menghasilkan no_aju (NOMOR PAB TERBIT).
    2. Memverifikasi penerimaan nomor aju dari Kemendag pada /api/receiveNomorAju berhasil memicu sinkronisasi lanjutan ke SITOLAUT.
    3. Memverifikasi ketahanan sistem (resilience) saat SITOLAUT mengalami kegagalan koneksi agar tidak terjadi hanging request.
  • Hasil Pengujian UAT: PENDING
  • Catatan QA:
Diagram Alur Pengujian E2E (SITOLAUT <-> PAB <-> KEMENDAG)
mermaid
sequenceDiagram
    autonumber
    actor QA as Tim QA / Tester
    participant PAB as Backend PAB (INSW)
    participant KEM as KEMENDAG
    participant SIT as SITOLAUT
    participant PEL as PELINDO
    Note over QA,PAB: Tahap 1: Inisiasi Pengajuan Data
    QA->>PAB: POST /pab/sitolaut/sendData (Data Baru)
    PAB->>KEM: Forward POST /receivePelaporan
    KEM-->>PAB: 200 OK (Data Diterima)
    PAB-->>QA: 200 OK (Mendapatkan nomor_layanan: 1030xxx)
    Note over QA,PAB: Tahap 2: Simulasi Penerbitan Nomor Aju Kemendag
    QA->>PAB: POST /pab/api/receiveNomorAju (id_referensi = nomor_layanan)
    par Sinkronisasi Downstream PAB
        PAB->>SIT: POST SITOLAUT_URL (Sync Dokumen Terbit)
        SIT-->>PAB: Status Response / Error Jaringan
    and
        PAB->>PEL: POST PELINDO_URL
        PEL-->>PAB: Status Response
    end
    PAB-->>QA: 200 OK (Keterangan status pengiriman downstream)

Skenario & Langkah Eksekusi Pengujian QA
TAHAP 1: Inisiasi Pengajuan Data Baru (SITOLAUT -> PAB)

QA mengeksekusi request pengiriman data pengajuan awal dari SITOLAUT ke INSW:

bash
curl --location 'https://dev-backend.insw.go.id/pab/sitolaut/sendData' \
--header 'Content-Type: application/json' \
--data-raw '{
    "header": {
        "id_referensi": 57790,
        "role": "pengirim"
    },
    "pelaku_usaha": {
        "npwp_pengirim": "866753425445326",
        "nib_pengirim": "9120204161003",
        "nama_pengirim": "CV Swadaya Mitra Sejahtera",
        "alamat_pengirim": "Tanjung Perak, Pabean, Surabaya",
        "kdprop_pengirim": "35",
        "kdkab_pengirim": "3578",
        "email_pengirim": "mitrasupplier@harakirimail.com",
        "telp_pengirim": "08976635357",
        "nama_cp_pengirim": "Anto",
        "npwp_penerima": "025081522941000",
        "nib_penerima": "9120001581307",
        "nama_penerima": "PT. Bumi Cendrawasih Permai",
        "alamat_penerima": "Jl. Kapitan malongi",
        "kdprop_penerima": "81",
        "kdkab_penerima": "8107",
        "email_penerima": "bcp.dobo@harakirimail.com",
        "telp_penerima": "0917-21123",
        "nama_cp_penerima": "Elizabeth",
        "npwp_ekspedisi": "123456789012345",
        "nib_ekspedisi": "0239010111439",
        "nama_ekspedisi": "PT. MITRA USAHA",
        "alamat_ekspedisi": "JL. KIcau TIMUR V NO.21, RT 001 RW 008 KELURAHAN ALAI PARAK KOPI, KECAMATAN PADANG UTARA, 2513",
        "kdprop_ekspedisi": "35",
        "kdkab_ekspedisi": "3578",
        "email_ekspedisi": "shipper@harakirimail.com",
        "telp_ekspedisi": "081338000780",
        "nama_cp_ekspedisi": "CORNELIUS HARIYANTO"
    },
    "muatan": {
        "jenis_pengiriman": "01",
        "jenis_kemasan": "01",
        "nama_kapal": "Nutech Testing",
        "pel_asal": "IDSUB",
        "etd": "2026-09-21",
        "pel_tujuan": "IDDOB",
        "eta": "2026-09-28",
        "alamat_tujuan": "Tanjung Perak, Pabean, Surabaya",
        "prop_tujuan": "81",
        "kab_tujuan": "8107",
        "prop_asal_tpk": "35",
        "kab_asal_tpk": "3578",
        "nama_operator": "DANANG",
        "trayek": "T-14 SBY-DBO",
        "voyage": "1"
    },
    "komoditi": [
        {
            "hs": "17019100",
            "uraian": "Gula",
            "jumlah": 100,
            "satuan": "KG",
            "kel_komoditi": "01",
            "jns_komoditi": "05",
            "subjns_komoditi": "08",
            "uraian_barang": "Gula Kristal Putih",
            "konversi_ton": 1
        },
        {
            "hs": "07032090",
            "uraian": "Bawang Putih",
            "jumlah": 10,
            "satuan": "KG",
            "kel_komoditi": "05",
            "jns_komoditi": "20",
            "subjns_komoditi": "61",
            "uraian_barang": "Bawang Putih",
            "konversi_ton": 0.1
        }
    ],
    "kontainer": [
        {
            "no_kontainer": "KONTAINER56",
            "tipe": 1,
            "ukuran": 20,
            "uraian": "DRY"
        },
        {
            "no_kontainer": "KONTAINER57",
            "tipe": 1,
            "ukuran": 20,
            "uraian": "DRY"
        }
    ]
}'
  • Ekspektasi Response Tahap 1:
    json
    {
        "code": 200,
        "nomor_layanan": "103009B7733D1",
        "message": "Berhasil Kirim Data No. Layanan : 103009B7733D1"
    }

IMPORTANT

  • Dinamisitas nomor_layanan: Nilai nomor_layanan (contoh: 103009B7733D1) yang dihasilkan pada response di atas pasti berbeda / acak pada setiap eksekusi data baru. Perbedaan nilai ini adalah kondisi normal dan bukan masalah.
  • Wajib Digunakan di Tahap 2: Nilai nomor_layanan riil yang didapatkan tersebut wajib dicatat dan disalin ke field id_referensi saat mengeksekusi request di Tahap 2 (POST /api/receiveNomorAju).
  • Kondisi Reset Data: Jika pesan response menampilkan "Berhasil Update Data...", artinya id_referensi tersebut sudah pernah terdaftar. Hubungi PIC Pengembang untuk mereset nomor referensi / data pengujian.
TAHAP 2: Penerimaan Nomor Aju Kemendag & Terusan ke SITOLAUT

Setelah dokumen terbit di Kemendag, Kemendag mengirimkan callback ke endpoint /pab/api/receiveNomorAju:

bash
curl --location 'https://dev-backend.insw.go.id/pab/api/receiveNomorAju' \
--header 'Content-Type: application/json' \
--data-raw '{
    "header": {
        "no_aju": "67790/INATRADE.1/PAB/LAP/10/2025",
        "tgl_aju": "2026-08-28 14:14:42.008",
        "url_dokumen": "https://inatrade.kemendag.go.id/#/sipt-docs/abc",
        "id_referensi": "103009B7733D1"
    }
}'

(Ganti id_referensi dengan nilai nomor_layanan dari Tahap 1, dan tgl_aju dengan timestamp waktu pengujian saat itu).

TAHAP 3: Evaluasi & Verifikasi Hasil Skenario
  1. Skenario A — SITOLAUT Online (Happy Path):

    • Ekspektasi Response: HTTP 200 OK
      json
      {
          "code": 200,
          "keterangan": "Data berhasil diterima, berhasil kirim sitolaut, namun gagal kirim pelindo"
      }
      (Catatan: Kegagalan kirim ke Pelindo pada environment dev/testing dapat diabaikan; titik kritis pengujian adalah konfirmasi berhasil kirim sitolaut).
    • Verifikasi Database & Log:
      • Database sipt.td_dokumen: status menjadi disetujui.
      • Database sipt.td_tracking_dokumen: tercatat status terkirim - sitolaut.
      • Grafana Log: Muncul log --> Incoming: POST /pab/api/receiveNomorAju dan log penutup <-- Completed: POST /pab/api/receiveNomorAju 200 (xxx ms).
  2. Skenario B — Penanganan Gangguan Jaringan SITOLAUT (Resilience & Partial Failure):

    • Kondisi: Endpoint SITOLAUT_URL sengaja diarahkan ke port/IP yang mati (ECONNREFUSED / timeout).

    NOTE

    Prosedur QA untuk Simulasi Error: Untuk mereproduksi skenario kegagalan koneksi ini, tim QA wajib berkoordinasi dan melakukan konfirmasi terlebih dahulu ke Tim Developer atau DevOps untuk mengubah nilai environment variable SITOLAUT_URL di server Staging sementara waktu (misal diarahkan ke http://127.0.0.1:9999 atau URL port mati), serta mengembalikannya ke URL normal setelah pengujian selesai.

    • Trigger / Request: POST /pab/api/receiveNomorAju dengan payload valid dari Tahap 2.
    • Ekspektasi Response: HTTP 200 OK (Response instan < 300ms, tidak menggantung / timeout).
      json
      {
          "code": 200,
          "keterangan": "Data berhasil diterima, namun gagal kirim sitolaut"
      }
    • Verifikasi Database & Log:
      • Database sipt.td_dokumen: tetap berstatus disetujui.
      • Database sipt.td_tracking_dokumen: mencatat status gagal terkirim - sitolaut.
      • Database sipt.logs: mencatat payload error socket koneksi ECONNREFUSED.
      • Grafana Log: Muncul log warning WARN: Data berhasil diterima, namun gagal kirim sitolaut dan log penutup <-- Completed: POST /pab/api/receiveNomorAju 200 (xxx ms).
  3. Skenario C — Validasi Data Nomor Layanan Tidak Terdaftar (Negative Case):

    • Pre-kondisi: Nomor layanan yang dikirim tidak pernah ada di tabel sipt.td_dokumen.
    • Trigger / Request: POST /pab/api/receiveNomorAju dengan id_referensi: "PAB-TIDAK-ADA".
    • Ekspektasi Response: HTTP 404 Not Found
      json
      {
          "code": 404,
          "error": "Nomor Layanan PAB-TIDAK-ADA tidak ditemukan"
      }
    • Verifikasi Database & Log: Grafana mencatat log selesai <-- Completed: POST /pab/api/receiveNomorAju 404 (xxx ms) dengan level warn.

PENGUJIAN TAMBAHAN: Otorisasi Safe Scope Check (Null / Undefined Scope)

(Bersifat umum untuk semua endpoint backend yang menggunakan middleware auth.doAuth)

  • Pre-kondisi: Token otorisasi memiliki payload tanpa field scopeGranted (bernilai null atau undefined).
  • Trigger / Request: Panggilan ke endpoint backend yang menggunakan middleware auth.doAuth.
  • Ekspektasi Response: HTTP 403 Forbidden
    json
    {
        "error": "invalid_access",
        "error_description": "Cannot access this module!"
    }
  • Verifikasi Error Handling: Sistem merespons semantik tanpa melempar fatal crash / TypeError di console server.
Bukti Verifikasi Staging (Diisi saat UAT)
json
{
  "status": "PENDING",
  "note": "Menunggu deployment Staging untuk eksekusi skenario uji QA dan capture log Grafana."
}

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