think
16px
820px

Setup lokal (macOS) — ahu-ocr-akta-notaris PoC

Untuk: agen Claude Code yang menjalankan setup di Mac lokal (macOS 26.5.2).
Tujuan: replikasi environment dev VM dev_3 supaya bisa bun test + jalanin app secara lokal.
Sumber kebenaran: ini di-generate dari .env + docker-compose.dev-db.yaml + package.json
VM dev_3 (2026-07-15). Ikuti persis; kalau ada yang gagal, laporkan — jangan menebak.


⚠️ Baca dulu — batas "bisa run di lokal"

App ini bergantung pada layanan on-prem AHU yang TIDAK ada di internet publik:

Layanan Alamat Dipakai untuk
GPU/OCR/LLM gateway 192.168.83.20:8200 classify, OCR (PaddleOCR), LLM cleanup/extract
SABH DB (MySQL) 192.168.72.102:3306 company lookup + registry state
PP registry (PG) 192.168.80.127:5434 pendirian PP lookup
Apostille registry (MySQL) 192.168.72.33:3306 apostille

Konsekuensinya, ada 2 mode:

  • Mode A — Dev logika + unit test (OFFLINE, direkomendasikan untuk mulai). Semua unit test murni
    jalan tanpa jaringan AHU — termasuk seluruh test berakhirnya yang jadi fokus branch ini
    (rules-berakhirnya, supporting-doc-classifier, bukti-pengumuman-extract). Cuma butuh Postgres lokal.
  • Mode B — Jalankan app end-to-end (BUTUH akses jaringan AHU). Upload → classify → OCR → extract
    perlu gateway :8200 + DB registry. Dari Mac lokal ini cuma jalan kalau kamu VPN ke jaringan AHU
    atau bikin SSH tunnel (lihat Lampiran A). Tanpa itu, app boot tapi tiap proses dokumen gagal/timeout.

Test integrasi yang memanggil gateway/registry akan gagal di Mode A — itu wajar, bukan bug branch ini
(cara membedakannya ada di bagian "Menjalankan test").


1. Prasyarat (macOS 26.5.2)

# Homebrew (kalau belum ada)
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

# Bun — WAJIB versi >= 1.3.14 (VM pakai 1.3.14)
brew install oven-sh/bun/bun    # atau: curl -fsSL https://bun.sh/install | bash
bun --version                   # pastikan >= 1.3.14 ; kalau kurang: bun upgrade

# Git
brew install git

# Postgres 16 — pilih SATU:
#  (a) Docker Desktop (paling mirip VM — Postgres 16 via container)  → brew install --cask docker
#  (b) Postgres native                                              → brew install postgresql@16

Node tidak wajib (semua lewat Bun + bunx prisma), tapi kalau mau aman: brew install node.


2. Clone repo + branch

Repo privat (akses SSH GitHub ke org Virtue-Digital-Indonesia diperlukan).

git clone git@github.com:Virtue-Digital-Indonesia/ahu-ocr-akta-notaris-POC.git
cd ahu-ocr-akta-notaris-POC
git fetch origin
git checkout fix/berakhirnya-status-badan-hukum   # branch kerja berakhirnya

Struktur yang relevan: backend/, frontend/, contract/ (shared, punya zod sendiri di root).


3. Install dependencies (TIGA lokasi — jangan lewat satu pun)

contract/ mengambil zod dari node_modules ROOT; backend & frontend punya deps sendiri.
Lupa bun install di root = error Vite Failed to resolve import "zod" from contract/review.ts.

bun install                 # ROOT — menyediakan zod untuk contract/  (WAJIB, sering terlewat)
cd backend  && bun install  # postinstall otomatis `prisma generate`
cd ../frontend && bun install
cd ..

4. Postgres lokal + buat database

App butuh 2 DB: ahu_ocr_dev3 (app) + ahu_ocr_dev3_test (test). Nama boleh apa saja asal DB test
berakhiran _test
(ada guard assertTestDatabase).

Opsi (a) — Docker (mirror VM persis)

docker run -d --name ahu-ocr-dev-db \
  -e POSTGRES_USER=ahu -e POSTGRES_PASSWORD=ahu_dev -e POSTGRES_DB=postgres \
  -p 5432:5432 postgres:16-alpine
# buat kedua database
docker exec -it ahu-ocr-dev-db psql -U ahu -d postgres \
  -c "CREATE DATABASE ahu_ocr_dev3;" -c "CREATE DATABASE ahu_ocr_dev3_test;"

(VM pakai port 47030; lokal pakai 5432 biar simpel — sesuaikan .env di langkah 5.)

Opsi (b) — Postgres native

brew services start postgresql@16
createuser -s ahu 2>/dev/null; psql postgres -c "ALTER USER ahu PASSWORD 'ahu_dev';"
createdb -O ahu ahu_ocr_dev3; createdb -O ahu ahu_ocr_dev3_test

5. File backend/.env

Buat backend/.env. DATABASE_URL/TEST_DATABASE_URL menunjuk Postgres lokal (port 5432).
URL layanan on-prem dibiarkan seperti VM — hanya terpakai di Mode B (butuh VPN/tunnel).
Secret (<ISI…>) minta ke Efran / salin dari .env VM hanya kalau kamu butuh fitur registry;
untuk test berakhirnya (Mode A) tidak diperlukan.

PORT=3001
DATABASE_URL=postgresql://ahu:ahu_dev@127.0.0.1:5432/ahu_ocr_dev3
TEST_DATABASE_URL=postgresql://ahu:ahu_dev@127.0.0.1:5432/ahu_ocr_dev3_test

# ── Layanan on-prem (Mode B; via VPN/tunnel — lihat Lampiran A) ──
OCR_PROVIDER=azure-on-prem
OCR_LAYOUT_PROVIDER=paddleocr
GPU_SERVER_URL=http://192.168.83.20:8200
CLASSIFIER_URL=http://192.168.83.20:8200/api/classifier/classify
CLEANUP_LLM_URL=http://192.168.83.20:8200/v1
AKTA_TXN_CLASSIFIER_URL=http://192.168.83.20:8200/v1
AKTA_TXN_CLASSIFIER_MODEL=Qwen/Qwen3.6-35B-A3B-FP8
JENIS_PERUBAHAN_EARLY_URL=http://192.168.83.20:8200/v1
JENIS_PERUBAHAN_EARLY_MODEL=Qwen/Qwen3.6-35B-A3B-FP8
AZURE_ON_PREM_BASE_URL=http://192.168.83.20:8200
AZURE_ON_PREM_API_KEY=
AZURE_ON_PREM_KTP_MODEL=indonesian_ktp_v4
AZURE_MODEL_NPWP=indonesian_npwp_v5
AZURE_MODEL_NPWP_LAMA=indonesian_old_npwp_v4
AZURE_MODEL_DOMISILI=domicile_statement_v3
AZURE_MODEL_CONTACT_INFO=contact_info_pt_v5
AZURE_MODEL_BUKTI_SETOR=deposit_statement_v4
AZURE_MODEL_SP_PENDIRIAN_PP=sp_pendirian_pp_v4
PADDLE_OCR_URL=http://192.168.83.20:8200
PADDLE_OCR_TIMEOUT_MS=300000
GPU_SERVER_TIMEOUT_MS=300000
KTP_EXTRACTION_SOURCE=paddleocr
NPWP_EXTRACTION_SOURCE=paddleocr
PASSPORT_EXTRACTION_SOURCE=paddleocr
DOMISILI_EXTRACTION_SOURCE=paddleocr
CONTACT_INFO_EXTRACTION_SOURCE=paddleocr
BUKTI_SETOR_EXTRACTION_SOURCE=paddleocr
SP_PENDIRIAN_PP_MODE=custom-model

# ── Registry eksternal — Mode B only. Untuk offline, matikan PP registry: ──
PP_REGISTRY_MODE=mock
# (kalau butuh real: PP_REGISTRY_MODE=real + isi host/kredensial di bawah)
# SABH_DB_HOST=192.168.72.102 ... SABH_DB_PASSWORD=<ISI>
# PP_REGISTRY_DB_HOST=192.168.80.127 ... PP_REGISTRY_DB_PASSWORD=<ISI>
# APOSTILLE_REGISTRY_DB_HOST=192.168.72.33 ... APOSTILLE_REGISTRY_DB_PASSWORD=<ISI>

SECURITY_JWT_SECRET=<ISI-string-acak-panjang>
SECURITY_DEV_LOGIN_SECRET=<ISI-string-acak-panjang>
MAX_FILE_SIZE_MB=20
VOTING_SWEEPER_ENABLED=false
VOTE_BASE_URL=http://localhost:3001

6. Prisma: generate client + push schema

cd backend
bun run db:generate        # prisma generate + regen contract/enums.gen.ts (JANGAN edit enums.gen.ts manual)
bun run db:push            # push schema ke DB APP (ahu_ocr_dev3), baca DATABASE_URL dari .env

Test DB — JANGAN pakai bun run db:push:test. Script itu hardcode localhost:5433/ahu_ocr_test
(sisa dari repo non-worktree) dan akan ke DB yang salah. Push ke test DB pakai TEST_DATABASE_URL:

DATABASE_URL="$(grep '^TEST_DATABASE_URL=' .env | cut -d= -f2-)" bunx prisma db push

Catatan: prisma db push tidak membuat trigger/fungsi SQL custom (mis. audit append-only) —
jadi beberapa test apostille/audit yang butuh trigger akan gagal. Itu pre-existing, bukan berakhirnya.


7. Menjalankan test

cd backend

# (A) Test fokus branch ini — MURNI, jalan OFFLINE, harus HIJAU semua:
bun test \
  src/flow-engine/__tests__/rules-berakhirnya.test.ts \
  src/services/__tests__/supporting-doc-classifier.test.ts \
  src/services/__tests__/bukti-pengumuman-extract.test.ts \
  --timeout 20000

# (B) Seluruh suite:
bun run test

Full suite akan punya sejumlah fail pre-existing (apostille/verifikator/admin — butuh trigger DB,
MinIO, atau jaringan registry). Cara memastikan tidak ada regresi dari perubahan kamu: bandingkan set
fail dengan/ tanpa perubahan pada environment yang SAMA:

git stash && bun run test 2>&1 | grep -oE '\(fail\) .*' | sed 's/ \[[0-9.]*ms\]$//' | sort -u > /tmp/base.txt
git stash pop && bun run test 2>&1 | grep -oE '\(fail\) .*' | sed 's/ \[[0-9.]*ms\]$//' | sort -u > /tmp/mine.txt
comm -13 /tmp/base.txt /tmp/mine.txt      # kosong = nol regresi

Typecheck: cd backend && bunx tsc --noEmit dan cd frontend && bunx tsc --noEmit
(ada 2–3 error pre-existing di file non-berakhirnya; file berakhirnya harus bersih).


8. Menjalankan app (Mode B — butuh gateway)

# terminal 1 — backend (baca PORT dari .env, mis. 3001)
cd backend && bun run dev
# terminal 2 — frontend (Vite; proxy /api ke backend)
cd frontend && VITE_API_PROXY_TARGET=http://localhost:3001 bun run dev
# buka http://localhost:5173  (port Vite default)

Kalau belum VPN/tunnel ke AHU, halaman jalan tapi setiap upload/classify gagal (gateway :8200
tak terjangkau). Sambungkan dulu lewat Lampiran A.


Lampiran A — Menjangkau layanan on-prem dari Mac lokal

Pilih salah satu:

  1. VPN AHU — kalau kamu punya akses VPN ke subnet 192.168.x, cukup itu; .env bisa dibiarkan
    apa adanya (URL 192.168.83.20:8200 dst. langsung kena).

  2. SSH tunnel lewat host yang bisa menjangkau 192.168.83.20 (mis. valserver):
    bash ssh -N \ -L 8200:192.168.83.20:8200 \ -L 3306:192.168.72.102:3306 \ developer@<valserver-ip>
    Lalu ubah .env supaya menunjuk localhost:
    GPU_SERVER_URL/CLASSIFIER_URL/CLEANUP_LLM_URL/AZURE_ON_PREM_BASE_URL/PADDLE_OCR_URL → http://localhost:8200/...
    dan SABH_DB_HOST=127.0.0.1 (port 3306). Biarkan tunnel terbuka selama app jalan.


Lampiran B — Gotcha yang sudah diketahui

  • bun install di ROOT wajib (untuk contract/ zod) — selain backend & frontend.
  • db:push:test salah target — pakai one-liner TEST_DATABASE_URL (langkah 6).
  • Test frontend yang render PDF gagal di headless (DOMMatrix is not defined, react-pdf/pdfjs) —
    pre-existing, bukan logika.
  • enums.gen.ts di-generate (bun run db:gen-enums) — jangan diedit tangan.
  • Fokus branch ini cuma butuh Mode A (offline + Postgres lokal). Untuk demo end-to-end pakai data
    sample nyata, perlu Mode B (gateway) — dan sample PDF berakhirnya ada di VM Efran, di luar repo
    (dokumen hukum, tidak boleh masuk git).
    ```