Rancangan: Kehadiran RUPS per Pemegang Saham — Ekstraksi dari Akta + Konfirmasi Manual
Status: draft desain · 2026-07-15
Tujuan
Status hadir/tidak-hadir per pemegang saham kini hanya bisa terisi dari Berita Acara (BA) RUPS. Tambahkan sumber akta (ekstraksi per orang) sebagai fallback, dan jadikan semua nilai otomatis wajib dikonfirmasi notaris. Berlaku untuk semua flow ber-RUPS: Perubahan, Akuisisi, Penggabungan, Peleburan, Pembubaran, Berakhirnya, Laporan RUPS.
Keputusan (final)
- Kuasa dihitung hadir →
kehadiranRupstetapBoolean?(kuasa/hadir → true, tidak_hadir → false, null unknown). Tanpa enum. - Konfirmasi = "Setujui Bagian" (section approval yang sudah ada), bukan per baris. Tidak ada kolom
confirmed, tombol konfirmasi per baris, atau badge per baris. Notaris meninjau roster (boleh koreksi via toggle), lalu menyetujui section-nya — itulah pengecekan/double-check-nya. - Backfill: hanya dokumen baru ke depan. Dokumen lama tetap null (manual/BA RUPS seperti biasa).
Prioritas sumber
Aturan:
- BA RUPS menang atas akta. Kalau BA RUPS diupload belakangan, nilai ber-source=akta boleh ditimpa jadi ba_rups. Nilai ber-source=akta tidak menimpa ba_rups.
- Manual menang atas semuanya. Nilai ber-source=manual (notaris toggle) tidak pernah ditimpa re-match.
- Konfirmasi keseluruhan lewat Setujui Bagian — bukan penanda per baris.
Model data
Tiap baris pemegang saham perlu jejak sumber + status konfirmasi.
Perlu satu penanda sumber saja (untuk precedence BA>akta + melindungi edit manual). confirmed tidak dipakai — konfirmasi via Setujui Bagian.
AktaPemegangSaham (deed roster — Perubahan/Akuisisi/Penggabungan/Peleburan, dan deed-path Pembubaran/Berakhirnya) — migrasi Prisma aditif (1 kolom):
kehadiranRups Boolean? // sudah ada — true (hadir/kuasa) · false (tidak) · null (unknown)
kehadiranSource String? // NEW: "ba_rups" | "akta" | "manual" | null
Submission.rupsKehadiranRegistry (registry fallback — Pembubaran/Berakhirnya) — JSON, tanpa migrasi:
{ nama, persentase, kehadiran, source?: "ba_rups"|"akta"|"manual"|null }[]
Perubahan per lapisan
1. Ekstraksi akta (per orang)
- Prompt
gpu-server/prompts/akta_perubahan.txt(dipakai semua flow perubahan-family incl. pembubaran/berakhirnya) — tambah ke tiap objekpemegang_saham:
"kehadiran_rups": "string|null — status kehadiran orang ini di RUPS: 'hadir' | 'kuasa' | 'tidak_hadir'; null bila akta tidak menyebut per orang (jangan menebak dari kuorum agregat)".
Grounding wajib: hanya isi bila akta benar-benar merinci per orang. - Schema
schema/akta-perubahan.ts—PemegangSahamKomposisi+ schema-doc: tambahkehadiran_rups?: string | null. - Transformer
field-transformer.ts—AktaPemegangSahamRecord+ mapping: bawakehadiran_rups, map string→boolean (hadir/kuasa→true,tidak_hadir→false, else null) via helper yang sama gayamapKehadiran. - Persist
document-processor.ts(aktaPemegangSaham.create) — setkehadiranRups+kehadiranSource: "akta"+kehadiranConfirmed: falsehanya bila akta memberi nilai; else biarkan null/null.
Operasional: prompt di gpu-server → perlu reload/restart + re-extract dokumen lama untuk backfill. Dokumen lama tetap null sampai di-extract ulang. Perubahan prompt memengaruhi kualitas ekstraksi semua flow yang memakainya.
2. Precedence di matcher
services/rups-attendance-matcher.ts — ganti guard if (kehadiranRups != null) continue jadi berbasis sumber:
if (source === "manual") continue; // edit notaris menang, tak pernah ditimpa
if (baMatch !== undefined) → set value + source="ba_rups"; // BA RUPS mengisi & menimpa akta/null
else if (source === "akta") keep; // pertahankan nilai akta bila tak ada BA
// akta-fill awal dilakukan di titik persist (bagian 1), bukan di matcher
Registry path: perlakuan sama atas field JSON source.
3. Edit (routes)
PUT .../kehadiran(sudah ada di pembubaran/berakhirnya) — set value +source="manual".- Perubahan/Akuisisi/Penggabungan/Peleburan sekarang read-only → tambahkan endpoint
PUT .../kehadiran+ jadikan roster bagian dari section yang di-Setujui Bagian. - Tidak ada endpoint confirm per baris — konfirmasi = section approval yang sudah ada di gate submit.
4. Frontend (semua flow ber-RUPS)
- Roster kehadiran editable: tombol Hadir / Tidak Hadir per baris (edit → source=manual).
- (Opsional) badge kecil sumber per baris ("BA RUPS" / "akta") — hanya info, bukan status konfirmasi.
- Jadikan roster Perubahan/Akuisisi/Penggabungan/Peleburan editable + bagian section yang bisa disetujui (kini read-only advisory).
- Konfirmasi keseluruhan tetap lewat tombol Setujui Bagian section RUPS/Kehadiran — tidak ada per-baris.
5. Tes
- Unit matcher: precedence ba_rups>akta>manual-preserve; BA RUPS upload belakangan meng-upgrade akta→ba_rups; source=manual tak ditimpa.
- Transformer/persist: map string kehadiran akta→boolean + source="akta".
- Routes: PUT set source=manual.
- FE: roster editable + Setujui Bagian di tiap flow.
Ringkasan dampak
+source +confirmed)] M --> X[matcher precedence] X --> R[routes: edit + confirm] R --> U[UI: badge + konfirmasi, semua flow] Mig[migrasi Prisma aditif] --> M
Fase implementasi yang disarankan
- Fondasi: migrasi Prisma (
kehadiranSource) + registry JSON field. Aman, dormant. - Precedence: rewrite matcher (ba_rups>akta>manual-preserve) + tes.
- Ekstraksi akta: prompt + schema + transformer + persist + tes (backfill hanya dokumen baru).
- Routes:
PUT kehadiran(+source=manual) untuk flow read-only. - UI: roster editable + Setujui Bagian di semua flow ber-RUPS (opsional badge sumber).
- Regression pass +
tsc/tes.
Keputusan (sudah diputuskan Efran 2026-07-15)
- Kuasa → dilipat ke
true(tanpa enum). - Konfirmasi → via Setujui Bagian (section approval), bukan per baris; tanpa gate submit tambahan.
- Backfill → hanya dokumen baru ke depan.