think
16px
820px

Signature Marker + Signer Gate + Field Contrast — Done Report (2026-07-13)

Status: DONE & DEPLOYED — app ahu-ai-ocr:02025e6a on staging :3520, signature service rebuilt on GPU 1 (ahu-signature-verify, healthy). Both suites green (backend 2537, frontend 970); everything re-verified live.


① Field contrast

Inputs sitting on white dialog surfaces (signer modal, edit dialog, voucher field) washed out — they now carry a visible border-foreground/20 + bg-muted/30 tint. Verified on the live modal.

② "Belum cocok di registri spesimen" is now an ERROR state

  • The signer card turns amber with an explicit "Belum cocok di registri spesimen" badge, the line "Permohonan belum bisa dikirim sampai pejabat penandatangan cocok di registri", and a prominent "Perbaiki — cari di registri / isi manual" button.
  • "Kirim ke Verifikator" is blocked until every signer is matched: the server's submit gate now rejects ANY non-MATCHED signer (previously only the ambiguous-candidates case), and the FE precheck mirrors it — verified live: the demo row's button is disabled with "1 dokumen belum cocok di registri spesimen — perbaiki pejabat penandatangan/penerjemah".
  • Note the consequence: a document whose signer genuinely isn't in the spesimen registry can no longer be submitted at all (matching via registry search or a manual entry that re-matches is the only path; the debug bypass remains for internal testing). Shout if you want an "acknowledge & proceed" escape for unregistered signers.

③ Signature bbox + manual draw

sequenceDiagram participant V as Verifikator/Pemohon participant FE as Review page participant BE as Backend participant S as ahu-signature-verify (GPU 1) S-->>BE: /verify → skor + doc_detection {page,x1..y2} BE-->>FE: signature.docBox (SignerMatch.signatureDocBox) V->>FE: "Lihat lokasi ttd di dokumen" FE-->>V: kotak tersorot di viewer (lompat ke halamannya) V->>FE: "Tandai tanda tangan manual" (deteksi gagal) FE-->>V: modal — seret kotak di halaman dokumen V->>BE: POST /signature-region {page,x1..y2} BE->>S: /verify + doc_box → crop manual dibandingkan S-->>V: skor baru + kotak manual tampil di viewer
  • Show the box: the service now returns its detected doc-side region; it's persisted (SignerMatch.signatureDocBox, migration 20260713010000) and surfaced on the advisory as "Lihat lokasi ttd di dokumen" — clicking highlights the exact rectangle in the document viewer and jumps to its page. A manually drawn box is labeled (manual).
  • Draw it when detection misses: on NO_SIGNATURE_DOC the advisory shows a prominent "Tandai tanda tangan manual" (plus "Tandai ulang" anytime) opening a new modal: the document page renders (pdf.js at 200 DPI / native image), you drag a rectangle around the signature, and "Simpan & bandingkan" re-runs the comparison cropping exactly that region.
  • Zero coordinate translation, by construction: the service renders PDFs at 200 DPI — the same GPU_IMAGE_DPI the viewers already use — and images at natural size, so detection boxes, drawn boxes, and viewer overlays all share one coordinate system.
  • Service round-trip verified on the rebuilt GPU container: auto-detect returned the correct box on a synthetic signature (score 0.35, match 100% vs itself); a manual doc_box was cropped exactly and echoed with manual: true, match 100%.
  • Sequencing note: the compare/draw affordances appear after the signer is matched (the comparison needs the officer's specimen) — the amber "fix the signer" flow above comes first, which is the intended order.