[ND-319/LNSW.34/2026] Penyesuaian Durasi Submission Cooldown 60 Detik, Auto-Release Lock Redis, dan Null-Safety Data NIB Pengajuan PAB
Modul: SIPT/PAB | Tipe: Bugfix | Stage Saat Ini:
DEVELOPMENT| Tanggal Dokumen: 2026-08-24
1. Informasi Tugas & Referensi Bisnis
- Task ID / Nomor Referensi:
ND-319/LNSW.34/2026 - Sumber Instruksi: Nota Dinas Resmi ND-319/LNSW.34/2026
- Dokumen Referensi / Lampiran: Permohonan Perbaikan Bug pada Aplikasi PAB.pdf (tersimpan pada direktori attachments jika ada)
- Modul Terkait:
SIPT/PAB - Service / Repository:
sipt-backend - PIC Pengembang: Hermansyah Efendi / Muhamad Firly Ramadan
- Latar Belakang & Ringkasan Kebutuhan: Berdasarkan evaluasi operasional dan laporan bug pada Nota Dinas ND-319/LNSW.34/2026 terkait aplikasi PAB (Pemberitahuan Arus Barang):
- Durasi submission cooldown pengajuan PAB sebelumnya bernilai 5 menit (300 detik) yang dinilai terlalu lama bagi pengguna ketika pengajuan membutuhkan pengiriman ulang atau saat terjadi error jaringan. Selain itu, lock Redis sebelumnya tidak langsung dilepas jika request selesai lebih awal atau terjadi kegagalan sistem, menyebabkan user tertahan cooldown yang tidak perlu.
- Terjadi runtime error
TypeError: Cannot read properties of undefined (reading 'trim')pada modul integrasi eksternal Kemendag dan skema validasi Zod ketika memproses data pelaku usaha yang memiliki nilainibataunib_penerimabernilai kosong (null/undefined). Proses bisnis PAB mengizinkan data NIB Forwarder (Ekspedisi) maupun Penerima kosong, sehingga diperlukan penanganan null-safety komprehensif.
2. Deployment Lifecycle
| # | Environment | Tanggal & Waktu | PIC | Status | Catatan |
|---|---|---|---|---|---|
| 1 | Development | 2026-08-24 13:43 | Hermansyah Efendi / Muhamad Firly Ramadan | DEPLOYED | Branch: development (Commit: ebd871dc) |
| 2 | Staging (UAT) | — | — | PENDING | — |
| 3 | Production | — | — | PENDING | — |
Riwayat Update Log
| Tanggal | Environment | Perubahan | PIC |
|---|---|---|---|
| 2026-08-24 | Development | Inisialisasi draft audit log dari context block backend (commit ebd871dc) | Hermansyah Efendi / Muhamad Firly Ramadan |
3. Analisis Teknis & Rincian Perubahan
Alur Logika & Bisnis:
- Optimasi Middleware Cooldown & Lifecycle Lock Redis (
app/middlewares/submission_cooldown.js):- Mengurangi konstanta
COOLDOWN_SECONDSdari 300 detik (5 menit) menjadi 60 detik (1 menit). - Mengimplementasikan monkey-patching pada lifecycle response Express (
res.end) agar otomatis memicu fungsireleaseLock()yang mengeksekusiredisClient.del(cacheKey)saat request selesai (finish/closemaupun error). Hal ini menjamin lock hanya menahan konkurensi selama proses berlangsung dan langsung dibebaskan pasca-eksekusi tanpa menunggu TTL habis.
- Mengurangi konstanta
- Null-Safety Integrasi Kemendag (
app/api/kemendag.api.js):- Menambahkan optional chaining operator (
?.trim()) pada pemetaan payloadekspedisi.nibdanpenerima.nib_penerimasaat pembentukan payload JSON integrasi Kemendag guna mencegah crash saat data bernilainullatauundefined.
- Menambahkan optional chaining operator (
- Null-Safety Penanganan Pembatalan Pengajuan (
app/controllers/newsend_sipt_controller.js):- Penanganan null-safety parameter pada pembatalan pengajuan PAB untuk menjamin konsistensi payload sebelum diteruskan ke service layer.
- Validasi Zod Schema & Whitelist Rule (
app/helpers/zod.js&app/validations/pelaku_usaha.validation.js):- Memperbaiki refinement rule skema Zod digit string agar menangani data kosong/nullable tanpa memicu validation error.
- Mengonfigurasi
nib_penerimamenjadi optional dan mendukung whitelist karakter0.
- Pembersihan Helper Manual Release (
app/helpers/kemendag-axios-interceptor.js):- Menghapus logika pelepasan manual lock Redis yang redundan pada interceptor axios karena pelepasan lock kini terpusat secara deterministik pada middleware
submission_cooldown.js.
- Menghapus logika pelepasan manual lock Redis yang redundan pada interceptor axios karena pelepasan lock kini terpusat secara deterministik pada middleware
- Optimasi Middleware Cooldown & Lifecycle Lock Redis (
Perubahan Database (DDL / DML):
sql-- Tidak ada perubahan skema database (DDL/DML) untuk task ini. -- Perubahan difokuskan pada middleware rate limiting/lock Redis, integrasi API Kemendag, dan Zod validation schema.Kontrak API & Response Payload:
- Endpoints Terkait:
POST /api/sipt/sendPOST /api/sipt/pelaku-usahaPOST /api/sipt/cancel
- Perubahan Behavior:
- Payload dengan properti
nibataunib_penerimabernilainull,"", atauundefinedkini diterima valid tanpa menghasilkan runtime error 500. - Waktu tunggu retry saat terjadi concurrent submission berkurang menjadi maksimal 1 menit, dan lock Redis dibebaskan seketika setelah request selesai dikembalikan ke client.
- Payload dengan properti
- Endpoints Terkait:
4. Bukti Teknis (Technical Proof & Audit Trail)
- Repository:
sipt-backend - Branch:
development - Commit ID / Hash:
ebd871dc5d343ae7ef7983e659c8ef773b18c434 - Merge Request / PR:
-
Cuplikan Kode / Implementasi Inti
javascript
// File: app/middlewares/submission_cooldown.js
const COOLDOWN_SECONDS = 60; // 1 menit
export const submissionCooldown = (action) => {
return async (req, res, next) => {
try {
const nomorLayanan = req.nomorLayanan;
if (!nomorLayanan) return next();
const cacheKey = CacheKeys.SUBMISSION_COOLDOWN(action, nomorLayanan);
const result = await redisClient.set(cacheKey, Date.now().toString(), "EX", COOLDOWN_SECONDS, "NX");
if (result === null) {
const ttl = await redisClient.ttl(cacheKey);
const minutesLeft = Math.ceil(ttl / 60);
throw new TooManyRequestsError(
`Pengajuan untuk nomor layanan ${nomorLayanan} sudah dikirim. Silahkan coba lagi dalam ${minutesLeft} menit jika status masih ${statusSipt.draft} atau ${statusSipt.gagal_kirim}.`
);
}
let released = false;
const releaseLock = async () => {
if (released) return;
released = true;
try {
await redisClient.del(cacheKey);
} catch (err) {
logger.error({ err, nomor_layanan: nomorLayanan, action }, "Failed to release submission cooldown lock");
}
};
// Monkey-patching res.end untuk auto-release lock saat request selesai/error
const originalEnd = res.end;
res.end = function (...args) {
releaseLock();
return originalEnd.apply(this, args);
};
next();
} catch (error) {
next(error);
}
};
};javascript
// File: app/api/kemendag.api.js (Null-Safety NIB)
ekspedisi: {
npwp: ekspedisi.npwp,
nib: ekspedisi.nib?.trim(),
tipe_perusahaan: ekspedisi.tipe_perusahaan,
nama: ekspedisi.nama,
// ...
},
penerima: {
jenis_tujuan: penerima.jenis_tujuan,
npwp_penerima: penerima.npwp_penerima,
nib_penerima: penerima.nib_penerima?.trim(),
nama_penerima: penerima.nama_penerima,
// ...
}5. Bukti Verifikasi Pengujian (QA / Unit Test / API Verification)
A. Verifikasi Unit Test (Development Stage)
- Test Suite Files:
tests/middlewares/submission_cooldown.test.jstests/validations/pelaku_usaha.validation.test.js
- Status Eksekusi CLI:
PASSED (7/7 tests passed)
javascript
// File: tests/middlewares/submission_cooldown.test.js
describe('submissionCooldown middleware', () => {
it('allows submission when Redis SET NX returns "OK"', async () => {
mockSet.mockResolvedValueOnce('OK');
res.end = vi.fn();
const middleware = submissionCooldown('receivePelaporan');
await middleware(req, res, next);
expect(mockSet).toHaveBeenCalledWith(
expect.stringContaining('cooldown:receivePelaporan:NL-001'),
expect.any(String),
'EX',
60,
'NX'
);
expect(next).toHaveBeenCalled();
});
});text
RUN v4.1.11 D:/WORK/LNSW/sipt-backend
✓ tests/validations/pelaku_usaha.validation.test.js (4 tests) 10ms
✓ tests/middlewares/submission_cooldown.test.js (3 tests) 7ms
Test Files 2 passed (2)
Tests 7 passed (7)
Start at 13:33:25
Duration 848ms (transform 351ms, setup 0ms, import 690ms, tests 18ms, environment 0ms)B. Verifikasi Integrasi Staging / Production
Diisi saat naik ke Staging atau Production.
json
{
"status": "PENDING",
"note": "Menunggu deployment ke environment Staging untuk pengujian end-to-end integrasi Kemendag dan verifikasi release lock Redis."
}- Hasil Pengujian UAT:
PENDING - Catatan QA: —