Peruri Front-End Compliance Checklist — what it is and where Obscura stands
Source: docs/PERURI/E-SIGNATURE/[VersionDate] Front End Compliance Checklist - [ClientName]-[version].docx
(NDA — gitignored; this file only summarizes our own compliance position).
Assessed: 2026-07-17, against the worktree build including the TERA stamp slice.
What the document is for
It is Peruri Digital Security's (PDS) pre-production acceptance review of the CLIENT's
front-end. Before they let an integration go live, a PDS QA engineer walks ~40 checklist
items across five areas, marks each PASSED/FAILED with UI screenshot evidence (the
appendix has capture sheets), and both PDS QA and their project manager sign the result.
We fill in client name, application name, portal URL and version; "PDS-CLIENT" — our
staging corporateId — is literally "a client of PDS".
The five areas: A certificate generation (registration + eKYC), B certificate
renewal, C document signing, D TERA / stempel elektronik, E JWT token usage.
Items marked Backend Checking are verified by PDS on their side from our API traffic;
the rest are UI requirements.
Compliance position by area
A. Generate certificate (items 1–14) — ✅ BUILT 2026-07-18 (staging live-proof pending)
The registration→eKYC→certificate journey is now the in-app activation wizard
(/activation), mock-proven end-to-end in a scripted browser run (including the live
camera capture). How each requirement is met:
- Consent checkbox with Peruri's exact wording + the CA legal-page link — a mandatory
checkbox AND a server-side hard gate (registration is rejected without it). - KTP upload ≤1MB (client + server enforced) with OCR autofill. Two extraction
paths share one seam: (a) a vision-capable LLM reads the image and returns the
fields directly (understands context); (b) for plain-text OCR engines
(PaddleOCR, Azure Document Intelligence "Read") a label-heuristic mapper
(KTPFieldsFromText) exploits the KTP's rigid printed layout (NIK/Nama/
Tempat-Tgl Lahir/Jenis Kelamin/Alamat labels + a 16-digit-run NIK fallback) to
produce the same fields. Either way OCR is a PRE-FILL the user reviews — never a
gate; no engine at all degrades to manual entry. NIK validated as exactly 16
digits and age ≥17 — both client-side AND re-validated server-side. - Email: the account email (already verified by our registration flow) IS the
provider identity. Phone: a dedicated verification step (OTP, attempts + TTL
capped); the registration always carries the VERIFIED number.
Delivery rides the WhatsApp Business Cloud API (admin-configured under
Admin → Security: phone-number ID + access token — encrypted at rest, masked in
the UI — and an optional approved authentication template). Development falls
back to a dev channel while unconfigured. Remaining external dependency: a Meta
WhatsApp Business account + an approved auth template. - Error handling surfaces the provider's own outcomes (email/NIK already registered,
etc.) as inline notifications. - Liveness video: recorded LIVE in the wizard via the browser camera
(getUserMedia + MediaRecorder) — there is deliberately NO file-upload path. Gesture
instructions shown (blink, open mouth, look right/left), auto-stop at 8 s, WEBM
(spec-accepted) ≤2MB enforced client + server. Failure states render the
"manual review / wait 1×24h" messaging; the attempt-cap state renders its own wait
screen. - Specimen: pick a saved signature (canvas-drawn or uploaded PNG) or draw one in the
wizard; the provider's 1MB cap is enforced at submission.
B. Renewal certificate (15–17) — ✅ BUILT
The wizard's expired state renders the SAME live camera capture (identical rules —
live-only, gestures, 8s, ≤2MB) and submits it to the provider's certificate-renewal
endpoint. Mock-proven end-to-end (expired → fresh video → active); staging live-proof
with the rest.
C. Signing document (18–32) — ✅ largely compliant today
- PDF-only ≤5MB: signing paths are PDF-gated; the provider's >5MB rejection maps to a
clean validation error. (A proactive client-side size check is a nice-to-have.) - Send with coordinates / order-ID handling (backend): the adapter sends the
placement rect at send time; identical semantics proven e2e with the mock provider. - Drag-and-drop signature placement UI: PASS —
PlaceSignatureModal(drag +
corner-resize over the rendered page). - Token entry UI (25–27): PASS —
SignOtpModalhas the code input (length-agnostic,
so 8-digit KEYLA tokens fit), a "Resend code" retry CTA, pending/progress states, and
distinct success/wrong-code notifications.
⚠️ Open point: the checklist words this as KEYLA (8-digit app token) while the
V1.4 spec still documents SMS/email OTP (and the V1.5 Postman collection has no OTP
folder). Ask Peruri which mechanism our corporate is provisioned with; the adapter
implements the OTP flow and has KEYLA endpoints ready. - ≥2 signers test (28): our envelope engine does multi-signer; the Sign-IT tier/parallel
mapping is planned after the single flow proves out on staging. If PDS requires it for
the review we map tier/parallel then, or demo System Signature. - Download signed/unsigned (29–30) and System Signature key valid/invalid (31–32)
(backend): implemented; System-Signature session HMAC is pinned against the spec's
worked example in a unit test.
D. TERA / stempel elektronik (33–38) — ✅ built (this session)
- Drag-and-drop stamp placement: PASS (
variant="stamp"of the placement modal). - Token entry UI for stamping + retry + progress (34–36): PASS — the stamp-flavored
OTP modal; success ("Digital stamp affixed") and wrong-code failure states proven in
a scripted browser run against the mock provider (screenshots archived). - Download stamped/not-stamped (backend): the shared seal completion path lands the
stamped version (statusstamped) and finalizes the stamp ledger; not-ready polls
return cleanly.
E. JWT token (39–40) — ✅ compliant
- Token generate with the real staging credentials works (verified live 2026-07-17).
- "Hit the token endpoint ~once a day": the adapter caches the bearer until its
23:59:59 WIB expiry and only regenerates on expiry/auth-class errors.
What actually goes to Peruri (data flows for area A)
Nothing is live-streamed and nothing goes browser→Peruri; every call is our backend →
Sign-IT REST API:
- Registration form: name, NIK, date of birth, email, phone, address, org fields —
plus the KTP photo as base64 (and NPWP photo if provided). Peruri is the CA; they
verify the identity against their sources. Sent once, in the form-user call. - Liveness video: recorded live in our UI, then uploaded once as base64
(H.264 or WEBM, ≤2MB, no MIME prefix) through our backend to the e-KYC endpoint —
an upload, not a stream. Success auto-issues the certificate; failure falls to
Peruri's manual review. - OCR: ours (client- or server-side), used only to pre-fill the form; the OCR
artifacts themselves are not sent — Peruri receives the final field values + the
KTP image. - Email/phone verification: our responsibility in our UI (Peruri's checklist
requires that we verified them); Peruri just receives the verified values. - Specimen: the signature image (≤1MB PNG) is uploaded to Peruri — it's what they
render into signed PDFs.
Bottom line
| Area | Status |
|---|---|
| A Generate certificate | ✅ wizard built + mock-proven; needs staging live-proof + a Meta WhatsApp Business account for the (built) OTP gateway |
| B Renewal | ✅ built + mock-proven |
| C Signing | ✅ minus staging live-proof; KEYLA-vs-OTP to confirm |
| D TERA stamp | ✅ built + mock-proven; staging live-proof pending |
| E JWT | ✅ |
Practical sequencing: with the wizard built, the full checklist scope (A–E) can go to
PDS review as soon as staging is unblocked and a phone-OTP gateway is wired. The KYC
gating requirement is also in: the PSrE tier is locked behind a warning + "Start
activation" prompt until the certificate is active, and stamping is blocked with
guidance until the user is TERA-registered.
Blocking item on Peruri's side (2026-07-17)
Staging credentials authenticate (token/generate → 00), but every corp-scoped call
returns 03 — User Tidak Diperkenankan: our clientId is not yet authorized for the
PDS-CLIENT corporate (unknown corp IDs return 02, so the corp exists and the token
is fine — it's the client↔corporate binding). Until PDS activates that (and TERA/cert
quota), no registration, signing, or stamping can run on staging.