Report: V2 read-only mode + route flip + legacy Pendirian PP review retirement
Worktree: /home/efran/remote-development/poc-ahu-ai/ahu-ocr-tidyup, branch refactor/tidyup-foundation.
Status: DONE
Commits (chronological)
6ddbd6a— feat(review-engine): readOnly prop threads ReviewEngine → section renderersa25c8ac— feat(pp-pendirian-v2): completed/read-only mode for the ReviewData engine page24f6f80— feat(pp-pendirian): flip /review to the V2 engine page, retire the legacy page9ae25f6— feat(pp-pendirian): retire the legacy GET .../review-data endpoint3b9e4b2— docs(pp-review-engine-mutations): fix comments left stale by the legacy page's retirement
(Note: 485c0b3 docs(pembubaran-pp): tenant #2 implementation plan sits between the branch's prior tip and commit 1 — that's a concurrent teammate's commit in this shared worktree, not mine; excluded from the summary above.)
What was done
Scope A — V2 completed/read-only mode (TDD)
components/review-engine/types.ts:SectionRendererPropsgainedreadOnly?: boolean.ReviewEngine.tsx: acceptsreadOnlyand forwards it to every section renderer.FieldListSection.tsx: Ubah + Konfirmasi/Unconfirm buttons getdisabled={readOnly}(rendered, not hidden — legacy idiom in engine terms).RosterSection.tsx: confirm/unconfirm icon button disabled whenreadOnly(combined with the existing per-rowrowConfirmGuarddisable).components/pp/pp-pemilik-manfaat-cards.tsx(BoCard +PpPemilikManfaatCards): confirm/unconfirm button and theKriteriaPickernow also disable onreadOnly.PpPendirianReviewPageV2.tsx:readOnly={isCompleted}passed intoReviewEngine.onRevalidateomitted entirely (not just disabled) when completed —ValidationBanneronly renders the revalidate button when the prop is present.- Pernyataan attestation
Checkboxes getdisabled={isCompleted}(pre-checked via the existing seed effect). - Finalisasi button area replaced with a completed banner (
data-testid="pendirian-completed-banner") whenisCompleted: emerald card +CheckCircle2+ "Pendirian PP — Selesai" + an "Unduh Packet" download button hitting the same/api/pp/pendirian/:id/packetendpoint the legacy page used — styled after the codebase's existingPeralihanCompletedBanner/PerbaikancompletedTitleidiom rather than a bespoke new one. - Stepper +
ReviewProgressHeadergating left untouched, as instructed.
Scope B — route flip + retirement (after Scope A green)
routes.tsx:pp/pendirian/:submissionId/reviewnow rendersPpPendirianReviewPageV2;.../review-v2now renders a new tinyPpPendirianReviewV2Redirectcomponent (components/pp/pp-pendirian-review-v2-redirect.tsx, mirrors the existingIndexRedirectconvention:useParams+<Navigate replace>) so old bookmarks land on/review. Legacy import removed.- Deleted
frontend/src/pages/pp/PpPendirianReviewPage.tsx(confirmed via grep:routes.tsxwas its only non-comment consumer) and its dedicated testfrontend/src/pages/__tests__/PpPendirianReviewPage.bo.test.tsx. hooks/use-pp-pendirian-review.ts: deletedusePpPendirianReviewDataanduseFinalizePpPendirian(confirmed sole consumer was the legacy page). Kept everything else —usePpEditField(and itsschedulePostEditRefetcheshelper, confirmed still used by it),usePpConfirmField/usePpUnconfirmField/useSetKbliConfirmed/usePpEditBoField/usePpEditKbli/usePpSetBoKriteria/usePpSetBoConfirmed/usePpDeleteBo/usePpSectionApproval, and allPpReview*types (still consumed by V2 + shared BO components per grep). Removed the now-unuseduseQueryimport.- Trimmed the now-dead
usePpPendirianReviewDatadescribe block out ofhooks/__tests__/use-pp-pendirian-review.test.tsx. - Backend
backend/src/routes/pp-pendirian.ts: deleted theGET /:id/review-datahandler andtoReviewField/the now-unusedPP_REVIEW_PHASE_RULE_CODESimport (both existed only to serve that handler). KeptppRequiredSections()per the brief, even though it's now unused — its doc comment and the finalize Gate-1 comment were reworded off the retired endpoint (they no longer claim finalize consults it, since it never actually did — the code only checkssectionApprovals["pernyataan"]). - Deleted
backend/src/review/__tests__/pp-pendirian-parity.test.ts(its sole purpose — parity-guarding the legacy vs. new payload while both endpoints lived — no longer applies) andbackend/src/routes/__tests__/pp-pendirian-bo-review-data.test.ts(tested only the deleted route). backend/src/services/__tests__/pp-pendirian-bo-e2e.integration.test.ts: its finalize-flow test fetched.../review-datapurely to readrequiredSectionsand approve each one. Since finalize's Gate 1 only ever checkssectionApprovals["pernyataan"](confirmed by reading the handler), replaced that step with a directpernyataanapproval — same test intent, no dependency on the deleted route.tidyup/tasks.mdline 64: PENDIRIAN_PP Phase B line updated to reflect route flipped + legacy endpoint/page retired (2026-07-04).- Small follow-up: two doc comments in
hooks/use-pp-review-engine-mutations.tsasserted the legacy page "keeps using" the old hooks "untouched" — now false since the page is gone; reworded to past tense (commit 5).
Test evidence
- Backend:
cd backend && bunx tsc --noEmit && bun run test→ typecheck clean; 1968 pass, 1 skip, 0 fail (245 files). - Frontend:
cd frontend && bunx tsc --noEmit && npx vitest run→ typecheck clean; 689 tests, 106 files, all pass. - New/changed test coverage added this task:
ReviewEngine.test.tsx(+2: readOnly passthrough, default-false),FieldListSection.test.tsx(+3: readOnly disables buttons / no-op click / default-false),PpPendirianReviewPageV2.test.tsx(+7: the COMPLETED-status describe block covering field/roster/BO-card/kriteria/pernyataan disabling, no Finalisasi, completed banner, no revalidate button). All were written first and observed failing (10 failing) before implementation, then green.
Deletions verified dead by grep (repo-wide, before deleting)
PpPendirianReviewPage(non-V2): onlyroutes.tsximported it; remaining hits after deletion are comments in unrelated files (use-pp-review-engine-mutations.ts,PpPeralihanPtReviewPage.tsx,lib/currency.ts,ReviewProgressHeader.tsx, backend projector/pp-shape.ts) — left alone as historical design-reference comments, except the two inuse-pp-review-engine-mutations.tsthat made an actively false current-state claim (fixed, commit 5).usePpPendirianReviewData/useFinalizePpPendirian: only the legacy page imported them.schedulePostEditRefetches: still used byusePpEditField— kept.- Backend
GET /:id/review-data: only 3 test files referenced the literal route/path; all handled (2 deleted, 1 patched).
Concerns
ppRequiredSections()is now genuinely unused dead code (kept per explicit instruction in the brief). Its only caller was the deleted endpoint; the finalize handler never actually called it (Gate 1 only checkspernyataan), despite an old comment implying otherwise — that comment is now corrected. Flagging in case the team wants it actually removed in a follow-up rather than kept indefinitely.- This is a shared worktree — a concurrent teammate committed
485c0b3(Pembubaran PP tenant-2 plan doc) mid-task. It's untouched by my diff and doesn't conflict, just noting it for traceability.