Apostille Smoke Wave — Done Report (2026-07-12)
Status: ALL DONE & DEPLOYED — staging ahu-ai-ocr:a14cada3 (192.168.83.20:3520). Both suites green (backend 2525, frontend 970); every fix re-verified live with scripted browser checks.
Review page …/81354581…/review
Q: Why "Nama pejabat penandatangan tidak terbaca dari dokumen"?
That demo submission's document (an ijazah PNG) has extractionStatus = ERROR — extraction failed entirely, so there was never a signer name to read. It only reached the verifikator because I force-submitted it with the debug bypass while seeding demo data; a real applicant can't submit while a document is un-extracted (the gate blocks it). Fixes shipped anyway:
- The signer block now distinguishes the two cases: extraction ERROR → "Dokumen gagal diekstraksi, sehingga data pejabat penandatangan tidak tersedia"; extraction OK but no name → "…biasanya karena nama tidak tercetak di dekat tanda tangan atau hasil pindai kurang jelas".
- When editable, the remedy is now a prominent button — "Cari pejabat di registri / isi manual" (opens the existing registry-search modal) — instead of the tiny footer link.
Upload page /apostille
- Jalur Percepatan is now a plain checkbox row (checkbox + one-line description). The big amber banner card is gone.
- KTP preview: the picked KTP shows an inline thumbnail (images directly; PDFs render page 1) — click it or the eye icon for the full preview.
- Step 1 → 2 slowness answered: it is neither extraction nor classification — the wait is the multipart file upload itself (KTP + N documents travel to the server in one request; the server responds immediately after storing them, and classification runs in the background with its own UI on step 2). Fix: a new XHR-based upload path streams real progress, and while uploading the whole form is replaced by a dedicated "Mengunggah N berkas… %" panel with a progress bar — no more spinning button. At 100% it switches to "Menyiapkan permohonan…" for the (sub-second) row creation, then navigates to the klasifikasi board, which already had its own "Mengklasifikasi dokumen…" state.
Klasifikasi board …/klasifikasi
- Empty lanes hidden: the board now shows only categories that hold documents. All categories appear as drop targets the moment you start dragging a card (the header copy says so). 12 empty dashed lanes gone.
Review page …/cee52830…/review
- "12 isian belum dikonfirmasi" / couldn't submit — root cause found, and it was a real bug (not spesimen). The submit gate was unsatisfiable from BOTH directions:
1. The projector exposed thedoc_signer_nameref as a gate-counted field, but it is never rendered as a confirmable row (the signer has its own block + modal) — so one item per document could never be confirmed. Now excluded from the gate absolutely via a new contract flag (confirmable:false), including under themanualConfirmAllmode staging runs.
2. The backend/submitcounted every non-LOCKED KTP field — including flagged fields outside the 11 curated identity keys the UI shows (your KTP's emptygolongan_darahwould have 409'd invisibly). It now counts exactly the curated keys + the 4 holder fields per document — the same set the UI renders.
Verified live: the button now enables with "Semua bagian terkonfirmasi". - Submit bar is full-page-width (moved out of the 62% column; the verifikator decision panel too — PT/PP parity).
- Progress header counts documents now: "Bagian 1/2 … 2/2 selesai" — the Dokumen Apostille/Legalisasi section is a first-class segment, and "Isian berikutnya" walks into it.
- Extra: when submit is blocked, the bar shows per-section chips ("Dokumen Apostille/Legalisasi: 1") that scroll-and-expand to the culprit section, and each document card gets a "Konfirmasi semua isian benar (N)" bulk action.
- "Negara tujuan … Layanan Apostille" restyled — a bordered chip + colored service badge instead of the plain text line.
- Zoom no longer breaks the page. Root cause: zooming set a fixed pixel width inside a
shrink-0flex column with nomin-width:0, so the column grew to fit, the viewer re-measured the wider container, multiplied by the zoom again — a runaway loop until the image covered the page.min-w-0added to the PDF column on all 14 review pages (the bug was latent everywhere); verified at 130% the viewer stays in its column and scrolls internally.
Jalur Percepatan without payment in scope — suggestions
The Rp500.000 is currently display-only. Three ways to make percepatan honest without building billing:
- Payment-reference field + verifikator attestation (recommended). Applicant fills an optional "Kode Billing / NTPN" text field at submit (payment itself happens on the real PNBP/SIMPONI rails, outside our app). The verifikator sees it as an advisory row and — for PERCEPATAN rows only — must tick "bukti pembayaran sudah diperiksa" before APPROVE (stored in the audit trail like decision notes). Zero external dependency, fully auditable, ~1 day of work.
- Pure attestation (lightest). Skip the reference field; just gate the PERCEPATAN approve behind the verifikator checkbox. Payment verification stays 100% out-of-band. Half a day.
- Dormant payment-status seam (most future-proof). Add a
fastTrackPaymentStatus(UNPAID → CLAIMED → VERIFIED) column + a manual "tandai terverifikasi" admin/verifikator action now, and a webhook endpoint stub — when a PNBP/SIMPONI integration becomes in-scope it plugs into the same states with no schema change. ~2 days.
Option 1 and 3 compose (1 is essentially 3's manual half). Say the word and I'll build whichever.
Also in this wave
- New shared
apiUpload(XHR) helper with progress + the same error envelope/401 handling asapiFetch. - Contract gains
ReviewFieldVM.confirmable?: boolean(single sharedcontract/review.tsused by both packages). - One pre-existing flaky FE test (klasifikasi kebab-reclassify) repeatedly tripped its 5s timeout under deploy-gate CPU load — raised to 15s.