think
16px
820px

K.35 — User-feedback wave: 2 security features shipped + full feedback triage

Deployed: ahu-ai-ocr:eb19e0b1 @ x056.ahu-demo.ocr.val.id · 2026-07-21
Suites: backend 2813 · frontend 1034 (0 fail)


Shipped now

1. Negative-case data redaction (PP flows) — "hanya ada redaksi 'data tidak valid'"

The leak was real and worse than the feedback implied: pembubaran PP projected the registered owner's name and UNMASKED NIK to the step-3 review regardless of identity-match outcome — anyone could probe a PP's real owner by starting a dissolution with a stranger's KTP. Perubahan/perbaikan leaked the same data through the diff's "semula" column, and three validation messages were oracles (similarity scores, registry-candidate enumeration).

Now, server-side (the payload never carries the data, so no client tweak reveals it):

  • A FAILED identity match (PP_PEMBUBARAN_OWNER_MATCH, PP_OWNER_DATA_KTP_MATCH, PP_ALAMAT_PEMILIK_KTP_MATCH, PP_*_NIK_IMMUTABLE) collapses the registered-data block to "Data tidak valid — identitas pemohon tidak sesuai dengan data terdaftar" and blanks every semula/before value in the diff to ••• (shape-agnostic walk — future diff parts can't reintroduce the leak). Overriding the FAIL does not un-redact.
  • Messages scrubbed: no more (skor 0.86) readouts, no more "Kandidat terdekat: …" registry enumeration (the manual picker keeps its chips — that's the same name+id data the public search serves).
  • Peralihan's pp_asal NIK is now masked server-side (3171********0007) — it used to leave the API raw with masking left to the frontend.

Verified live: a seeded pembubaran with a failed owner match → the review payload contains zero registered values and only the redaction notice.

2. Post-approval audit lock — "LOCKED after it has been approved"

One API-layer middleware: any mutating request naming a terminal submission — directly or through one of its documents — is refused with 409 SUBMISSION_LOCKED ("Transaksi telah disetujui dan terkunci untuk keperluan audit"). Reads stay open (audit = read-only, not invisible).

  • Terminal is verifikasi-aware, not just status = COMPLETED: PT-perubahan-family rows sit at COMPLETED while the verifikator pipeline (decisions, shareholder voting, PERBAIKAN loops) legitimately writes — those lock only when the verifikasi reaches SELESAI/DITOLAK. Flows whose COMPLETED is final (pendirian, laporan RUPS, apostille) lock immediately; KEDALUWARSA locks too.
  • This is the foundation for the requested history features (KBLI change history, share buy/sell history, historical tree): approved rows can no longer shift, so history can be derived from them trustworthily.

Verified live: COMPLETED submission → mutation 409 with the lock message; GET still 200.

Bonus find while verifying: staging was silently broken

The PR #2 merge added Submission.rupsKe + AktaPemegangSaham.kehadiranSource to the schema without a migration — staging 500'd on every full-row Submission read (pembubaran/perubahan reviews) while all 2800+ tests stayed green (the test DB syncs via db push, not migrations). Wrote the catch-up migration (20260721020000), verified via prisma migrate diff that the migrations folder now exactly reproduces the schema. Worth telling the dev/2 team: schema change ⇒ migration file, always.


Triage of the remaining feedback (priority levels)

Priority scale: P0 = now/next wave · P1 = soon, design is clear · P2 = needs product decision or external dependency · P3 = out of our scope / other team.

Apostille

Item Read Priority Notes
"spesimen pejabat baru → perlu input spesimen baru" When the signing officer is NEW (not yet in the registry), there must be a way to register their specimen P1 We already built the applicant-side attachment (K.30/31 tangguhan + Keterangan Keabsahan). What's missing is the OFFICIAL intake: a verifikator/admin surface that promotes a validated new specimen into the registry. Needs a write path to the specimen store — currently we are read-only on it → confirm with AHU whether we may write, or hand off to the registry's own intake.
"pengecekan cap dan ttd dari NOTARIS, ttd notaris masuk ke form" Verify the notary's own stamp+signature on apostille docs, and capture it P1 Same machinery as officer signature-verify (detector + compare) pointed at the notary. Needs a notary-specimen source (SABH has notaris data; specimen availability unknown → 1-day recon first).

Perseroan Perorangan

Item Read Priority Notes
Flow perubahan PTP → PT The PP-to-PT conversion flow DONE This is PERALIHAN_PP_KE_PT — built and live. If they mean something different (e.g. initiated from the PP side), needs one clarifying question.
Negative-case redaction DONE Shipped this wave (above).

PT

Item Read Priority Notes
"merger & akuisisi masih manual gapapa, skip dulu" Permission to deprioritize P3 (explicitly skipped) Penggabungan/akuisisi flows exist; no further polish until asked.
"summary data Bank yang sering dipakai pemegang saham → monitoring" Monitoring view: which banks shareholders transact through P1 The data exists (Daftar Setoran facts: bank, rekening, pengirim per shareholder). Build = an admin analytics view aggregating transferFacts across submissions. Clear scope, ~1 wave.
"perubahan KBLI minta ditampilkan history-nya" KBLI change history per company P1 Unlocked by the audit lock. Derivation: ordered COMPLETED PERUBAHAN_PT/PP submissions per company → KBLI diffs per step. Needs a company-keyed index of approved submissions.
"peralihan saham minta ditampilkan history-nya" Share transfer history P1 Same derivation over pemegang-saham diffs. Do together with KBLI history (one "riwayat" engine, two lenses).
"historical tree — admin level, atau di detail saham(?)" A company-level history tree P2 Build after the two histories above prove the data; the open "(?)" is a product decision (admin-only vs shareholder detail).
"standarisasi nomor telepon (kode negara, kode wilayah)" Normalize phone numbers P1 (small) Deterministic normalizer (+62 handling, area codes) applied at extraction + a validator. Half-day.
"akun korporasi dengan lampiran surat pernyataan — menunggu PT rebuild" Corporate accounts w/ statement letter P2 (blocked) Explicitly waits for the PT rebuild to land.

Chatbot (engine repo — hands-off for us; prepare integration prompts instead)

Item Priority Notes
Internal data-request use case: adjust prompt + AHU-approved redaksi P1 (other repo) Wording/prompt change in ai-ahu-chatbot; we can draft the prompt + redaksi pack for that session.
External tiers: umum = 5 questions max; logged-in = process/ticket checks (estim?); AI can't answer → route to call center P2 Needs product decisions (quota mechanics, estim integration, ticket source). We can spec the gating; implementation lives in the chatbot repo.

Verifikator

Item Read Priority Notes
SLA: idle 2 days → escalate to katimja (FIFO) Work-queue escalation P1 We have per-verifikator queues + timestamps; add an SLA sweep (cron) + escalation state + katimja view. Needs the katimja role defined (persona split makes this easy).
"cuti → jangan masuk transaksi" Leave status removes a verifikator from assignment P1 (pairs with SLA) Simple availability flag consulted by assignment; admin UI toggle.
"history transaksi: dipindah oleh siapa, dari mana" Assignment/transfer audit trail P1 An assignment-event table (who moved what, from→to, when). Pairs naturally with the audit lock's philosophy; feeds the SLA view.

Out of topic (recorded, mostly other teams)

Item Priority Notes
KTP 2-arah validation (Dukcapil × Kemendagri) → "bank data AHU" P2/P3 Needs government API access agreements — beyond this codebase. Our KTP extraction is ready to feed it.
DB encryption + access restriction P2 (real, ours partially) On-prem Postgres: enable at-rest encryption + tighten pg_hba/roles on the GPU host; the app already never exposes the DB. Worth a hardening pass with ops.
e-materai (Peruri) untuk surat pernyataan — permintaan dirjen P2/P3 Commercial/legal integration; our docx/pdf generation can embed once the Peruri API contract exists.
"cek ke P2 dokumen yang perlu e-materai" P3 An inquiry task, not a build.

Suggested order for the next waves

  1. P0/P1 quick wins: phone normalization · verifikator cuti flag · assignment history table (they're small and independent).
  2. History engine (KBLI + share transfer on top of the audit lock) — the feedback's clearest recurring theme.
  3. SLA escalation (needs katimja persona) + bank-usage monitoring view.
  4. Apostille new-specimen intake + notary signature check (after the registry-write question is answered).

Commits

66e42836 redaction + audit lock + tests
eb19e0b1 catch-up migration for dev/2's un-migrated columns