Codebase Navigation Cheatsheet — AHU-OCR (dev_4)
A practical guide to going from "this is broken" → "that file" without knowing the whole system. Written around the real bugs we fixed so the examples are concrete.
The one trick that solves 80% of cases
Copy the exact text you see on screen (or in an error) and grep for it. Almost every user-visible string lives, verbatim, in the file that produces it.
cd backend # or frontend
grep -rn "Tidak ditemukan" src # → the KBLI rule that emits this message
grep -rn "Dokumen belum lengkap" src # → the gate that blocks "Lanjut"
Indonesian UI text is usually in a frontend component; validation/error messages are usually in a backend service. Grep both if unsure.
The mental model
BACKEND (backend/src/) FRONTEND (frontend/src/)
───────────────────────── ─────────────────────────
routes/ URLs → handlers pages/ one file per screen
services/ business logic hooks/ fetch + mutate (API calls)
lib/ DB clients, config components/ reusable UI pieces
flow-engine/ which rules run routes.tsx URL → which page
review/ build the review screen lib/ types + helpers
prisma/ database schema main.tsx app setup
Data flows left to right on each side, and the frontend talks to the backend through hooks/ → routes/.
Backend: where things live
| Folder | What's in it | Example from our fixes |
|---|---|---|
routes/ |
HTTP endpoints (one file per area). A URL like /api/submissions/:id/review maps to a handler here. |
routes/review-data.ts = the review screen's data + finalize |
services/ |
The actual logic. Validation rules, the OCR/extraction pipeline, matching. | services/cross-validator-kbli.ts = KBLI validation rules |
lib/ |
Low-level clients & config. Database pools, logger, config.ts. |
lib/sabh-db.ts = the SABH MySQL connection |
flow-engine/rules/ |
Which rules run for which flow. | flow-engine/rules/pt-akta/index.ts lists PT's validation rules |
review/projectors/ |
Turn stored data into the shape the review page needs. | review/projectors/pt-pendirian-review.ts |
prisma/schema.prisma |
The database tables. | — |
Trace example (the KBLI fix): user sees "Tidak ditemukan: 62019" →
grep -rn "Tidak ditemukan" backend/src → services/cross-validator-kbli.ts (the rule) →
it calls validateKbliCodes in lib/sabh-db.ts (the DB query). That's the whole chain: service → lib.
Frontend: where things live
| Folder | What's in it | Example |
|---|---|---|
pages/ |
Full screens, one per route. | pages/PtPendirianReviewPageV2.tsx = the Tinjauan (review) screen |
components/ |
Reusable UI blocks used by pages. | components/pendirian/validation-results.tsx = the "Hasil Validasi" panel |
hooks/ |
Everything that talks to the backend (TanStack Query). | hooks/use-submission.ts (useOverrideValidation, etc.) |
routes.tsx |
The URL → page map. Start here to find which file a URL renders. | pendirian/:id/review → PtPendirianReviewPageV2 |
lib/ |
Shared types + formatters. | lib/submission-types.ts (ValidationResultItem) |
Trace example (the override UI): "there's no way to override a validation on the review screen" →
routes.tsx tells you the review URL renders PtPendirianReviewPageV2.tsx →
it renders <ValidationResults> from components/pendirian/validation-results.tsx →
which calls useOverrideValidation from hooks/use-submission.ts →
which POSTs to routes/submissions.ts on the backend. page → component → hook → route.
Symptom → where to look first
| Symptom | Start here |
|---|---|
| A screen looks wrong / is blank | frontend/src/pages/<Screen>.tsx, then the hooks/ it calls |
| A button is disabled / a gate blocks you | The page's gate logic (grep the tooltip text), e.g. PendirianExtractionPage.tsx |
| A validation says the wrong thing | backend/src/services/cross-validator*.ts (the rule) + flow-engine/rules/<flow>/index.ts (whether it runs) |
| Data from SABH is missing/wrong | backend/src/lib/sabh-db.ts (queries) + services/sabh-*.ts |
| An API call 404s or errors | backend/src/routes/<area>.ts (grep the URL path) |
| A field was extracted incorrectly | backend/src/services/document-processor.ts |
| "Which validation rules apply to flow X?" | backend/src/flow-engine/rules/<flow>/index.ts |
How to confirm you found the right file
- Read the test next to it. Most logic files have a
*.test.ts(backend) or*.test.tsx(frontend) sibling, often in a__tests__/folder. The test names describe the behavior in words. - Run just that test to see it pass/fail:
bash cd backend && bun test src/services/__tests__/cross-validator-kbli.test.ts cd frontend && node node_modules/.bin/vitest run src/components/pendirian/__tests__/validation-results-override.test.tsx - Follow the imports at the top of the file — they point to the next link in the chain.
Useful grep recipes
# Which page does a URL render?
grep -n "pendirian/:submissionId" frontend/src/routes.tsx
# Which file emits an on-screen message?
grep -rn "SABH database tidak tersedia" backend/src
# Where is a function defined vs. used?
grep -rn "validateKbli" backend/src # definition + all callers
# Which rules run for a flow?
sed -n '1,60p' backend/src/flow-engine/rules/pt-akta/index.ts
Rule of thumb: grep the words, follow the imports, read the test. Those three moves locate almost anything.