Blackbox Testing — Laporan RUPS Tahunan (PT)
- Domain: PT
- Fitur: Laporan RUPS Tahunan (Pelaporan RUPS Tahunan, UUPT Pasal 66-68)
- Role/aktor: notaris (input & finalisasi), admin (akses menyeluruh). Tidak ada tahap verifikator (flow terminal self-service).
- Tanggal uji: 2026-08-19
- Penguji (sesi): Supervisor PT
- Build/commit: 63c40a17
1. Ringkasan fitur
Laporan RUPS Tahunan memproses paket dokumen laporan tahunan perseroan (Akta atau Risalah RUPS Tahunan sebagai dokumen utama, ditambah laporan keuangan dan sejumlah lampiran) untuk mencatatkan pelaporan tahunan ke SABH. Notaris mengunggah paket lewat papan Klasifikasi, sistem menjalankan OCR, ekstraksi, dan pencarian perseroan pada registri, lalu menampilkan halaman tinjauan berisi identitas perseroan, field akta, pilihan tahun laporan dan jenis audit, data akuntan publik, serta hasil validasi. Notaris memilih tahun laporan dan jenis audit, menyetujui tiap bagian wajib, lalu mengirim lewat tombol Kirim Laporan (Final). Flow ini terminal: begitu dikirim, statusnya langsung COMPLETED tanpa antrean verifikator, karena pelaporan tahunan adalah pengajuan administratif dan SABH tidak membuat baris verifikasi untuk alur ini. Ini adalah tenant pertama yang memakai mesin generic v2 (engine: v2-generic).
2. Full workflow
2.1 Diagram state
stateDiagram-v2
[*] --> CREATED
CREATED --> EXTRACTING: POST /start
EXTRACTING --> AWAITING_COMPANY_SELECTION: lookup perseroan tidak menemukan 1 kecocokan pasti
AWAITING_COMPANY_SELECTION --> VALIDATING: pilih perseroan (select-company)
EXTRACTING --> VALIDATING: 1 kecocokan pasti langsung lanjut
VALIDATING --> READY: aturan validasi dijalankan
READY --> COMPLETED: Kirim Final (atestasi + bagian wajib disetujui + tidak ada FAIL tersisa + WARNING diakui)
COMPLETED --> [*]
EXTRACTING --> ERROR: kegagalan OCR/ekstraksi akta
2.2 Sequence (aktor - sistem)
sequenceDiagram
actor N as Notaris
participant FE as Frontend
participant BE as Backend :47014
participant OCR as OCR/LLM
participant REG as Registri SABH (read-only)
N->>FE: Unggah paket (akta + laporan keuangan + lampiran) di /klasifikasi
FE->>BE: POST /api/klasifikasi/upload + /classify (per berkas)
OCR-->>BE: AKTA_RUPS_TAHUNAN / LAPORAN_KEUANGAN / OTHER
FE->>BE: POST /api/submissions (infer LAPORAN_RUPS_TAHUNAN)
FE->>BE: POST /api/submissions/:id/start
BE->>OCR: ekstraksi field akta + focused pass laporan keuangan
BE->>REG: companyLookup (nama_perseroan + nomor_sk)
REG-->>BE: kandidat kecocokan
alt tidak ada kecocokan pasti tunggal
BE-->>FE: status AWAITING_COMPANY_SELECTION
N->>FE: pilih perseroan
FE->>BE: POST /api/perubahan/select-company/:id
end
BE->>BE: jalankan aturan validasi, status READY
FE->>BE: GET /api/laporan-rups/submissions/:id/review-data (poll)
N->>FE: pilih tahun laporan + jenis audit, konfirmasi field, setujui bagian
FE->>BE: PUT /tahun-laporan, PUT /jenis-audit, POST /sections/:key/approve
N->>FE: Klik Kirim Final, akui tiap WARNING
FE->>BE: POST /api/laporan-rups/submissions/:id/submit
BE-->>FE: { status: COMPLETED, rupsSubmittedAt }
2.3 Peta route & UI
| Langkah |
Route |
Komponen |
Elemen interaktif utama |
Selector |
| Unggah & klasifikasi paket |
/klasifikasi |
KlasifikasiPage |
dropzone/file input, papan doc-type (assign lampiran) |
input[type=file], tambah-dokumen-input |
| Ekstraksi (step 2) |
/laporan-rups/:id/extraction |
LaporanRupsExtractionPage |
auto-start pipeline, progres |
(tanpa testid stabil) |
| Tinjauan (step 3) |
/laporan-rups/:id/review |
LaporanRupsReviewPage |
pilih tahun laporan, radio jenis audit, konfirmasi field akta, setujui bagian, override FAIL, input akuntan publik, tombol Kirim Final, dialog deklarasi |
tombol berbasis teks (tanpa testid stabil) |
| Status (step 4) |
/laporan-rups/:id/status |
LaporanRupsStatusPage |
ringkasan tercatat, kembali ke dashboard |
(tanpa testid stabil) |
3. Prasyarat & data uji
| ID data |
Tipe |
Berkas |
Deskripsi |
Ekspektasi sistem |
| D-TW |
Positive |
paket tidak_wajib_audit/ (akta_notaris + laporan_keuangan) |
Paket non-audit, 2 dokumen scan asli |
Terklasifikasi LAPORAN_RUPS_TAHUNAN, mencapai READY, jalur kirim sampai COMPLETED |
| D-WA |
Positive |
paket wajib_audit/ (akta + 6 lampiran) |
Paket wajib audit, 7 dokumen scan asli |
Terklasifikasi LAPORAN_RUPS_TAHUNAN, mencapai READY; AKUNTAN_PUBLIK_REQUIRED aktif saat WAJIB_AUDIT |
| D-WAN |
Negative (varian D-WA) |
paket wajib audit tanpa data akuntan publik |
Set WAJIB_AUDIT tanpa mengisi akuntan |
AKUNTAN_PUBLIK_REQUIRED FAIL; kirim terblokir karena bagian akuntan-publik belum disetujui |
Catatan data uji: berkas adalah scan asli (bergitignore) di e2e/data/real-intake/pt/laporan_rups/. Karena scan, mutasi berbasis text-layer (pdf-factory) tidak dipakai; negative case digali lewat variasi jenis audit dan kelengkapan data akuntan. Bukti tersimpan di e2e/artifacts/laporan-rups/ (results.json + 3 screenshot UI).
4. Matriks skenario uji
| ID |
Tipe |
Lapisan |
Langkah ringkas |
Ekspektasi |
Hasil aktual |
Status |
Bukti |
| TC-01 |
Positive |
API |
Unggah paket D-TW, klasifikasi, submission, start, poll |
Terklasifikasi AKTA_RUPS_TAHUNAN (0.9992), type LAPORAN_RUPS_TAHUNAN, akhirnya READY |
Sesuai: akta 0.9992; paket park di AWAITING_COMPANY_SELECTION lalu READY setelah pilih perseroan |
PASS |
results.json (TW) |
| TC-02 |
Positive |
API |
Poll status paket D-TW |
Sampai READY (2 dokumen) |
Sesuai: READY, 2 dokumen, 8 hasil validasi |
PASS |
results.json |
| TC-03 |
Gate |
API |
Submit sebelum atestasi & persetujuan bagian |
Ditolak |
400 SECTIONS_UNAPPROVED (bagian wajib belum disetujui dievaluasi lebih dulu) |
PASS |
results.json (gate_before_attestation) |
| TC-04 |
Gate |
API |
Submit saat FAIL masih berdiri (setelah atestasi + setujui bagian) |
422 VALIDATION_FAILED |
Sesuai: failing=[RUPS_AKTA_FIELDS_PRESENT] |
PASS |
results.json (gate_with_fails) |
| TC-05 |
Gate |
API |
Override RUPS_AKTA_FIELDS_PRESENT dengan alasan |
Boleh (overridable) |
200 OK |
PASS |
results.json (overrideOutcomes) |
| TC-06 |
Positive |
API |
Set NON_AUDIT + tahun valid, konfirmasi field, setujui bagian, override FAIL, akui WARNING, submit |
COMPLETED |
Sesuai: {submitted:true, status:COMPLETED} |
PASS |
results.json (finalSubmit) |
| TC-07 |
Positive |
API |
Unggah paket D-WA (7 dokumen), poll |
READY |
Sesuai: READY, 7 dokumen |
PASS |
results.json (WA) |
| TC-08 |
Positive |
API |
Set WAJIB_AUDIT tanpa data akuntan |
AKUNTAN_PUBLIK_REQUIRED FAIL |
Sesuai: FAIL "belum lengkap: nama_akuntan_publik, tanggal_izin_akuntan_publik" |
PASS |
results.json (akuntanRuleWajibNoData) |
| TC-09 |
Negative |
API |
Submit wajib audit tanpa isi akuntan & tanpa setujui bagian akuntan |
Terblokir |
400 SECTIONS_UNAPPROVED missingSections=[akuntan-publik] |
PASS |
results.json (negative_submit_wajib_missing_akuntan) |
| TC-10 |
Positive |
API |
Isi data akuntan publik + setujui bagian akuntan |
AKUNTAN_PUBLIK_REQUIRED PASS |
Sesuai: PASS "Data akuntan publik lengkap" |
PASS |
results.json (akuntanRuleWajibWithData) |
| TC-11 |
Positive |
API |
Cek AKUNTAN_IZIN_FORMAT dari laporan keuangan asli |
WARNING untuk format tidak AP.xxxx, PASS untuk AP.1234 |
Sesuai: izin registri KAP asli "01308/..." WARNING; input "AP.1234" PASS |
PASS |
results.json (izinFormat) |
| TC-12 |
Positive |
UI |
Deep-link /laporan-rups/:id/review saat READY |
Halaman render, tombol Kirim Final disabled |
Sesuai: header + semua bagian tampil, tombol disabled |
PASS |
ui-review-gate.png |
| TC-13 |
Gate |
UI |
Setelah atestasi + setujui bagian + override FAIL, buka review |
Tombol Kirim Final enabled, dialog deklarasi muncul |
Sesuai: enabled, dialog "Kirim Pelaporan RUPS Tahunan" tampil |
PASS |
ui-submit-dialog.png |
| TC-14 |
Positive |
UI |
Buka review submission COMPLETED |
Redirect ke status "Laporan Tahunan Tercatat" |
Sesuai: redirect ke /status, teks final tampil |
PASS |
ui-status-completed.png |
Ringkasan validasi paket D-TW saat READY: 2 FAIL (RUPS_AKTA_FIELDS_PRESENT, AKUNTAN_PUBLIK_REQUIRED sebelum atestasi jenis audit di-set), 3 PASS (TAHUN_LAPORAN_VALID, OLD_DATA_CONSISTENCY, PERSEROAN_STATE), 7 SKIPPED, 1 WARNING (RUPS_LAMPIRAN_COMPLETENESS). Setelah set NON_AUDIT, AKUNTAN_PUBLIK_REQUIRED menjadi SKIPPED sehingga hanya RUPS_AKTA_FIELDS_PRESENT yang perlu di-override.
5. Cakupan UI (semua yang diakses user)
| Route/Elemen |
Diuji? |
Perilaku benar? |
Catatan |
/klasifikasi unggah paket |
Ya (via API drive) |
Ya |
Klasifikasi menghasilkan AKTA_RUPS_TAHUNAN / LAPORAN_KEUANGAN; lampiran perlu assign manual di papan (lihat OBS-2) |
/laporan-rups/:id/extraction |
Tidak (dilewati via API) |
- |
Auto-start pipeline; belum ada testid stabil (rekomendasi) |
/laporan-rups/:id/review render |
Ya |
Ya |
Identitas Perseroan, Akta, Tahun & Jenis Audit, Akuntan Publik, Lampiran, Hasil Validasi semua tampil |
| Pilih tahun laporan (dropdown) |
Ya (API) |
Ya |
Opsi dari server-anchored window (createdAt-10..-1), bukan jam browser |
| Radio jenis audit (WAJIB/NON) |
Ya (API) |
Ya |
Membalik required bagian akuntan-publik di gate |
| Tombol Setujui Bagian |
Ya (API) |
Ya |
Baris eksplisit, bukan turunan konfirmasi field |
| Tombol Kirim Final (gate) |
Ya |
Ya |
disabled saat atestasi belum lengkap / FAIL berdiri / bagian belum disetujui |
| Dialog deklarasi + ack WARNING |
Ya |
Ya |
Deklarasi kebenaran data + centang tiap WARNING wajib |
/laporan-rups/:id/status |
Ya |
Ya |
"Laporan Tahunan Tercatat", teks final, tanpa timeline verifikator |
| Panel verifikator |
N/A |
- |
Tidak ada (flow terminal self-service) |
6. Temuan bug & perbaikan
| ID bug |
Severity |
Ringkas |
Reproduksi |
Ekspektasi |
Aktual |
Screenshot |
Rekomendasi perbaikan |
| OBS-1 |
Med (ekstraksi) |
Field akta RUPS tahunan kosong dari scan asli |
Unggah paket D-TW/D-WA, buka review-data |
nomor_akta & tanggal_akta terekstrak |
akta.fields kosong ([]) meski extractionStatus DONE; di paket D-WA akta bahkan extractionStatus ERROR. RUPS_AKTA_FIELDS_PRESENT FAIL |
results.json (TW.aktaFields, WA classifiedDocs) |
Akta RUPS tahunan menumpang extractor "perubahan" (overrideByClassifiedType). Untuk scan asli extractor ini tidak menghasilkan field, sehingga notaris selalu harus override FAIL wajib SABH. Selidiki prompt/skema ekstraksi khusus akta RUPS tahunan atau retry ekstraksi |
| OBS-2 |
Med (desain) |
Lampiran tidak pernah terisi otomatis |
Unggah lampiran (kegiatan/TJSL/pengawasan/dll) |
Slot lampiran terisi setelah klasifikasi |
Klasifikasi melabeli lampiran sebagai AKTA_RUPS_TAHUNAN atau OTHER; label halus LAMPIRAN_* tidak pernah diproduksi classifier, semua 6 slot tetap kosong |
results.json (lampiranSlots) |
Sesuai desain (label halus adalah assignment manual di papan doc-type), tetapi berarti upgrade "wajib audit = 7 dokumen" tidak dapat dipenuhi lewat unggah saja tanpa remap manual. RUPS_LAMPIRAN_COMPLETENESS hanya WARNING sehingga tidak memblokir. Pertimbangkan classifier lampiran atau petunjuk assign yang jelas |
| OBS-3 |
Low (reliability) |
Kecocokan perseroan tidak pasti untuk data asli |
Unggah paket dengan perseroan nyata |
Idealnya 1 kecocokan pasti |
Paket park di AWAITING_COMPANY_SELECTION; diselesaikan lewat select-company manual. Untuk D-WA registri malah menandai PT terblokir (PERSEROAN_STATE FAIL "Pemblokiran karena dibuka sementara untuk akses perubahan dirkom") |
results.json (WA.validations) |
Wajar untuk registri read-only lokal; bukan cacat. Catat bahwa PERSEROAN_STATE bisa FAIL nyata dan (per kode) dapat di-override sebelum submit |
| OBS-4 |
Low (UI/uji) |
Tidak ada data-testid stabil di halaman laporan RUPS |
Tulis uji UI |
Selector stabil |
Uji UI bergantung pada teks tombol/heading |
screenshots |
Tambah data-testid pada tombol Kirim Final, dialog deklarasi, dan banner status untuk uji yang tahan perubahan teks |
Catatan urutan gate (bukan bug): submit route mengevaluasi persetujuan bagian sebelum atestasi tahun/jenis. Saat mencoba submit tanpa apa pun, kode yang muncul lebih dulu adalah SECTIONS_UNAPPROVED, bukan ATTESTATION_INCOMPLETE. Keduanya benar sebagai gate; hanya urutan pesan yang perlu diketahui saat membaca error.
7. Ringkasan & rekomendasi
- Total skenario: 14 (PASS 14 / FAIL 0). Semua skenario API dan UI lolos.
- Cakupan UI: 8 dari 9 elemen inti diuji langsung di browser (extraction step dilewati via API; sisanya tercakup). Route review, dropdown tahun, radio jenis audit, gate Kirim Final, dialog deklarasi, dan status terminal semua terverifikasi.
- Bug: High 0, Med 2 (OBS-1 ekstraksi field akta kosong, OBS-2 lampiran perlu assign manual), Low 2 (OBS-3, OBS-4).
- Mekanisme finalisasi: route sendiri
POST /api/laporan-rups/submissions/:id/submit (bukan finalize engine generik). Gate berurutan: atestasi tahun+jenis audit, persetujuan bagian wajib (akuntan-publik ikut wajib saat WAJIB_AUDIT), checkFailGate (block-with-override, envelope 422 VALIDATION_FAILED), lalu deklarasi + akui setiap WARNING, dalam satu transaksi ke COMPLETED. COMPLETED tercapai (terbukti API dan UI) tanpa tahap verifikator.
- Logika kewajiban audit terbukti benar: NON_AUDIT membuat AKUNTAN_PUBLIK_REQUIRED SKIPPED dan bagian akuntan-publik tidak wajib disetujui; WAJIB_AUDIT mengaktifkan FAIL saat data akuntan (dokumen laporan keuangan + nama + nomor izin + tanggal izin) belum lengkap dan menjadikan bagian akuntan-publik wajib disetujui. Persyaratan dokumen lampiran (5 lampiran naik jadi wajib saat wajib audit) diformalkan di papan doc-type, tetapi RUPS_LAMPIRAN_COMPLETENESS hanya WARNING sehingga tidak memblokir submit.
- Kuorum RUPS tidak divalidasi untuk alur ini (dikonfirmasi di kode:
RUPS_TAHUNAN_RULE_SET sengaja tidak menyertakan RUPS_ATTENDANCE_QUORUM; pelaporan tahunan adalah pengajuan administratif, bukan keputusan voting).
- Rekomendasi prioritas: (1) perbaiki ekstraksi field akta RUPS tahunan agar nomor & tanggal akta terisi tanpa override (OBS-1); (2) sediakan classifier atau alur assign lampiran yang jelas agar upgrade wajib-audit dapat dipenuhi (OBS-2); (3) tambah
data-testid untuk uji UI yang stabil (OBS-4).
- Gap/keterbatasan: field akta tidak terekstrak dari scan asli sehingga uji berbasis nilai field (mis. TAHUN_BUKU_ORDERING, RUPS_ANNUAL_WINDOW yang butuh tanggal_rups) tidak dapat dibuktikan positif dari data ini (semuanya SKIPPED karena tanggal_rups tidak terbaca). Pencocokan perseroan memakai registri SABH read-only sehingga hasil bergantung data registry nyata.