Kenapa kontrak data ini ada
Sebelum backend GiziFin dibangun, tim produk lebih dulu menyepakati bentuk data yang dipakai di seluruh aplikasi, termasuk untuk data mock yang berjalan saat ini. Tujuannya sederhana: begitu API sungguhan dibangun, kontraknya sudah jelas dari awal, dan navigasi antar entitas (misalnya dari alert ke SPPG yang dirujuknya) tidak lagi kehilangan ID di tengah jalan. Referensi ini merangkum entitas-entitas utama tersebut.
Entitas inti
SPPG menyimpan identitas satuan pelayanan: nama, provinsi, kabupaten/kota, koordinat, kapasitas produksi harian, status aktif atau tidak, serta nomor Virtual Account-nya. Vendor menyimpan identitas pemasok bahan baku. Transaction mencatat satu transaksi pembelian, lengkap dengan komoditas, satuan, jumlah, nilai dalam rupiah, dan statusnya (selesai, terlambat, dibatalkan, atau dikoreksi).
Benchmark menyimpan harga acuan per komoditas, satuan, dan wilayah untuk satu periode tertentu, termasuk sumber dan versi datanya. DailyReport mencatat laporan operasional harian dari satu SPPG, sementara DistributionEvidence menyimpan bukti distribusi makanan ke kelompok penerima manfaat. Evidence adalah entitas umum untuk dokumen pendukung seperti struk belanja, laporan harian, bukti QR distribusi, atau foto, masing-masing dengan status validasinya sendiri.
Kode alasan dan skor risiko
Setiap penilaian risiko disusun dari beberapa RiskComponent, masing-masing dengan bobot dan skor mentahnya sendiri. Komponen-komponen ini digabung menjadi satu RiskAssessment yang menyimpan skor akhir, daftar komponennya, dan kode alasan yang menyertainya.
Kode alasan sendiri berasal dari daftar tertutup yang sudah ditetapkan, di antaranya harga di atas benchmark regional, satuan harga yang tidak sebanding, ketidaksesuaian volume dengan bahan baku, ketidaksesuaian laporan distribusi, kesenjangan aktivitas SPPG, konsentrasi vendor yang tidak wajar, dana idle di atas ambang, ketidaksesuaian struk transaksi, laporan harian yang hilang, bukti distribusi yang hilang, referensi struk ganda, dan kualitas data yang tidak memadai. Setiap kode menyimpan aturan yang dipakai, ambang batas, nilai aktual, nilai pembanding, sumber, dan versi mesin aturan yang menghasilkannya. Satu detail yang sengaja dijaga: kualitas data disimpan terpisah dari skor risiko, karena data yang tidak lengkap bukan bukti risiko yang lebih tinggi.
Alert dan alur statusnya
Alert punya empat tipe: ketidakwajaran harga, ketidaksesuaian volume, kemungkinan tidak aktif, dan dana idle. Status alert mengikuti alur yang sudah ditentukan, dimulai dari baru, lalu bisa berpindah ke diakui atau ditandai duplikat. Dari diakui, alert berlanjut ke dalam tinjauan, lalu bisa berpindah ke menunggu klarifikasi, dieskalasi, atau diselesaikan. Alert yang sudah diselesaikan masih bisa dibuka kembali kalau diperlukan. Alur ini bukan sekadar tampilan tombol, tapi aturan yang benar-benar memvalidasi perpindahan status mana yang diperbolehkan.
Kasus dan rekonsiliasi
Satu kasus bisa menaungi beberapa alert sekaligus, dengan status, prioritas, dan penanggung jawabnya sendiri. Setiap kasus yang diputuskan menyimpan jenis keputusannya (selesai tanpa masalah, selesai karena kesalahan data, selesai dengan tindak lanjut, atau dieskalasi) beserta alasan terstruktur yang wajib diisi.
Rekonsiliasi bekerja dengan menyandingkan empat jenis sumber: transaksi bank, bukti belanja, laporan harian, dan bukti distribusi. Setiap proses rekonsiliasi punya versinya sendiri, karena menjalankan ulang proses tidak menimpa hasil sebelumnya. Kalau ada baris yang tidak cocok, jenis selisihnya dicatat, entah itu selisih nilai, volume, waktu, atau identitas.
Jejak audit
Setiap tindakan yang berdampak, seperti mengubah status alert, membuat kasus, meminta klarifikasi, mengeskalasi, atau menyelesaikan kasus, tercatat sebagai satu peristiwa audit. Setiap peristiwa menyimpan siapa pelakunya, tindakan apa yang dilakukan, entitas mana yang terdampak, referensi kondisi sebelum dan sesudah perubahan, serta alasannya jika ada. Untuk tindakan berdampak tinggi, alasan ini menjadi wajib diisi.