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 everysemula/beforevalue 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_asalNIK 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
- P0/P1 quick wins: phone normalization · verifikator cuti flag · assignment history table (they're small and independent).
- History engine (KBLI + share transfer on top of the audit lock) — the feedback's clearest recurring theme.
- SLA escalation (needs katimja persona) + bank-usage monitoring view.
- 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 |