The official system of record for every PETRA MoU and MoA.
The working app, on demo data. Sign in with a demo account to see the dashboard, queues and renewals.
SIM Kerjasama
The working app, running on demo data. It loads here, inside the page.
Partnership documents used to live in inboxes and folders. SIM Kerjasama gives each one a single, traceable path.
Approvals follow the official hierarchy, and every delay is visible.
One clean, evidence-based partnership dataset that other systems can rely on.
Active partnerships open to the whole university, and to partners as PETRA.
Modelled in BPMN from the rules the database enforces: who acts, in what order, and which status each step sets.
A unit proposes, the International Office routes it, approvers decide tier by tier, and the signed document is activated.
A tier opens only when no lower tier in the current round is still waiting. Empty tiers are skipped.
Approve opens the next tier. Revise asks for a new draft while the SLA keeps running. Pending freezes the document and its clock. Reject archives it.
Counted in business days from when the approver's tier opens, excluding weekends, holidays and time in Pending. Yellow at 2 days, red at 4.
The office can record a document signed outside the system directly, so the dataset is complete from day one.
As an agreement nears its end date, the unit and the partner each evaluate it, and renewal opens only on evidence.
Monthly from six months before the end date, then weekly for the last two months. The expiry sweep runs daily at 05:15 WIB.
The owning unit evaluates in the app; the lead partner evaluates through a secure link, without an account.
Renewal opens only when both evaluations agree, or when the office overrides with a recorded reason.
Activating the renewal links it to the old agreement and archives the old one in a single transaction.
The two processes above, in one line.
Propose. A unit proposes an agreement, or records one already signed.
Tap a card.

Valid agreements and their documents are ready for BAN-PT and LAM assessors.

Domestic and international MoU/MoA counts are available at any time, without a manual recap.

A dependable count of international partners and countries for QS and THE submissions.

Every decision, revision and renewal stays on record when staff change.
Transcribed from the source repository: migrations, functions, README and rules. The database owns the business rules; the app calls into it.
Access control is RLS; tier gating and SLA are Postgres functions. They behave the same from a Server Action, a sweep or the read API.
No client-side data fetching and no internal API routes. Each action is a thin call into the function that owns the rule.
RLS still decides which rows a view returns, so reporting never leaks.
Every archival records a reason: rejected, expired_without_renewal, superseded_by_renewal or terminated_early.
| Layer | Choice |
|---|---|
| Frontend | Next.js 15 (App Router, typed routes), React 18, TypeScript, Tailwind CSS 3 |
| Backend | Supabase: Postgres 17, Auth, Storage, Row-Level Security, Edge Functions, pg_cron |
| Domain logic | Postgres functions: tier gating, business-day SLA with pause, unit cascade, renewal gate |
| Charts / map | ECharts (Studio Grafik), Leaflet (Peta Mitra Global) |
| Exports | ExcelJS (.xlsx) |
| kirim-email Supabase Edge Function via Resend | |
| Hosting | Vercel (frontend), Supabase (database and functions) |
Pick a step: the functions it calls, the tables it writes, the status it sets and the rules that guard it. The touched tables light up in the ERD.
The proposal and its child rows (partners, proposers, Lingkup units, agendas, fields, SDGs, MoU/MoA detail).
simpan_anak_proposal()proposal_dokumenpartner_pengusulpengusulproposal_dokumen_unitproposal_dokumen_agendastatus_proposal = Draft
Highlighted in amber: proposal_dokumen, partner_pengusul, pengusul, proposal_dokumen_unit, proposal_dokumen_agenda.
Documents near their end date move to Akan Berakhir; reminders are queued monthly from 6 months out, weekly for the last 2. Auto Renewed documents are skipped.
sapu_kedaluarsa()catat_notifikasi()dokumen_kerja_samanotifikasiAktif → Akan Berakhir
Rules: K-06
Highlighted in amber: dokumen_kerja_sama, notifikasi.
The core of the SIM Kerjasama schema, grouped by domain. Select a table to trace its relationships.
Select a table to highlight its relationships. Scroll the diagram in both directions.
negara
id (PK), kode, nama, is_domestic
unit
id (PK), nama, id_parent_unit (FK), id_jenis_unit (FK), is_active
jabatan
id (PK), nama, id_unit (FK), tier_disposisi
akun
id (PK), auth_user_id (FK), id_jabatan (FK), email, role, +1
partner
id (PK), nama, is_international, id_negara (FK), latitude, longitude, id_merged_into (FK), +10
partner_contact
id (PK), id_partner (FK), nama, email, +2
agenda
id (PK), nama, is_amendment
proposal_dokumen
id (PK), jenis_kerjasama, status_proposal, tujuan_kerjasama, manfaat_bagi_petra, id_dokumen_sebelumnya (FK), id_akun_pembuat (FK), waktu_disetujui, status_sla, +8
partner_pengusul
id_partner (FK), id_proposal_dokumen (FK), is_lead
pengusul
id_jabatan (FK), id_proposal_dokumen (FK)
proposal_dokumen_unit
id_proposal_dokumen (FK), id_unit (FK)
proposal_dokumen_agenda
id_proposal_dokumen (FK), id_agenda (FK)
proposal_status_history
id (PK), id_proposal_dokumen (FK), status_lama, status_baru, waktu
disposisi
no (PK), id_proposal_dokumen (FK), no_dokumen_kerjasama (FK), jenis_disposisi, round_ke, id_akun_pengirim (FK), +3
disposisi_target
no (PK), no_disposisi (FK), id_jabatan (FK), tier, status, waktu_unlock, batas_waktu_sla, durasi_hari_kerja, status_sla, +1
riwayat_approval
id (PK), id_disposisi_target (FK), id_proposal_dokumen (FK), id_akun (FK), aksi, catatan, +2
revisi_proposal
id (PK), id_proposal_dokumen (FK), file_proposal, id_disposisi_target_peminta (FK), +3
pending_periods
id (PK), id_proposal_dokumen (FK), mulai, selesai, +2
dokumen_kerja_sama
no (PK), id_proposal_dokumen (FK), no_dokumen, tanggal_mulai, tanggal_berakhir, status, alasan_arsip, upload_dokumen, +6
evaluasi
no (PK), id_dokumen_kerjasama (FK), respondent_type, id_partner_contact (FK), id_jabatan_pengusul (FK), rekomendasi, status, id_supersedes (FK), +15
partner_eval_token
id (PK), id_evaluasi (FK), token, is_active, waktu_submit, +4
keputusan_pembaruan
id (PK), id_dokumen_kerjasama (FK), keputusan, alasan, +2
notifikasi
id (PK), id_proposal_dokumen (FK), no_dokumen_kerjasama (FK), id_jabatan_penerima (FK), jenis_notifikasi, status, +3
implementasi_dokumen
no (PK), no_dokumen_kerjasama (FK), jenis, judul, status, +5
FK* = logical reference to a view or registry, checked by a function because views cannot be foreign-key targets.
| ID | Rule | Enforced by |
|---|---|---|
| K-01 | A target unlocks when no lower-tier target in the current round is still unapproved; an empty tier is skipped. recompute_tiers is the single idempotent writer of this state. | Function |
| K-02 | SLA is per target, from unlock, in business days excluding weekends, holidays and time in Pending. Yellow at 2, red at 4; thresholds come from settings. | Function + pg_cron |
| K-03 | A revision overwrites the draft in place and is logged in revisi_proposal. No other target is affected and the SLA clock keeps running. | Function |
| K-04 | Pending freezes the document and stops the SLA clock. Reactivation starts a new round from tier 1, including tiers that had already approved. | Function |
| K-05 | Reject is terminal; the document is archived with alasan_arsip = rejected. | Function |
| K-06 | A renewal proposal can be created only when both evaluations are submitted and both recommend continuing, or KUI recorded an override with a reason. | buat_proposal_perpanjangan |
| K-07 | The public surface is exactly two anon-executable functions, each requiring a 256-bit token scoped to one evaluation. | Grants |
| K-08 | An account may act on a document only while an open disposisi_target is routed to its jabatan and is pending_action. | RLS |
| K-09 | Documents are never hard-deleted; every archival records one of four reasons. | CHECK + functions |
| K-10 | While a document is in disposition IO can add targets (they join the current tier) or remove pending ones; an approved target cannot be removed. | tambah_target / hapus_target |
proposal_dokumen.status_proposaldokumen_kerja_sama.statusdisposisi_target.statusalasan_arsipakun.rolejenis_kerjasama_tsimks-sapu-sla → sapu_sla()pg_cron 22:00 UTC (05:00 WIB)Recompute SLA, set flags, queue yellow, red and escalation reminderssimks-sapu-kedaluarsa → sapu_kedaluarsa()pg_cron 22:15 UTCMove documents to Akan Berakhir, archive expired ones, queue expiry reminderskirim-email Edge FunctionEvery 5 minutesSend pending notifikasi rows via Resend, after the transaction commits