JDIH OIKN
OIKN's public legal document portal, with a controlled publishing workflow and AI summaries that never leave the server

- documents sent to outside AI services
- 0
- access tiers, checked at every download
- 3
- roles matching the legal directorate's sign-off
- 5
- public and admin pages
- 36
On this page
The problem
Otorita IKN is a new government body, and it issues its own legal instruments: regulations, decrees, cooperation agreements and more. Before this system, those documents sat in email threads and on local drives. The public had no way to find an official OIKN regulation. There was no controlled review, so anyone with server access could publish anything. Access to sensitive documents was handled informally, with no record of who saw what. The yearly activity report required by OIKN Head Regulation No. 14 of 2025 was assembled by hand.
JDIH is Indonesia's national legal information network, and every agency must run a compliant portal. OIKN needed one with a public side for citizens and a controlled workflow for its Directorate of Law.
What I built
Roles that follow the legal directorate
The plan had four roles. In practice it needed five, to match how the directorate works. Legal directorate admins and data stewards can approve documents, and data stewards also handle access requests. Other admins can create and edit documents, but can never approve them. This split came with single sign-on, when it became clear who signs off in the real organisation. Every admin action declares which roles may use it, and the review page is closed to anyone who can't approve.
Access tiers checked at the download
Every document is open, restricted or closed. Restricted documents still appear in search, with a button to request access. A data steward approves the request, with an optional expiry date. Before showing a button, the page asks the server what this person may do: download, request access, or log in. The file link is never sent to someone who can't open it, and every access and download is logged.
AI summaries that never leave the server
I first shipped document summaries through an outside AI service, to prove the feature was worth building. A day later I rebuilt the pipeline to run fully on OIKN's own server, because sending government legal documents to a third-party service is a compliance risk. It pulls the text from each PDF, picks the key sentences into a plain-language summary, and tags the legal field. Over the following month I added a way to check its quality. Staff can write a corrected summary for any document, and a weekly job compares the output against those corrections to catch drift.
A map of which rules change which
A background job reads new document titles for legal citation phrases, such as "revoking Regulation No. 14 of 2022". It finds the document being cited and proposes a link for an admin to confirm. Confirmed links form a public tree showing which regulations revoke, amend or implement each other.
Statistics computed overnight
The admin dashboard and the public statistics page never count documents live. A nightly job fills summary tables, so both pages stay fast as the collection grows. The public page shows a year-long activity heatmap, trending document types and the most-read legal fields. If the nightly table is still empty, the dashboard reads the activity log so it never shows a false zero.
Result
JDIH OIKN is in production. The Directorate of Law uses it to draft, review and publish documents, and the public portal serves open documents to anyone. Staff sign in through OIKN's single sign-on, and outside users sign in with email and password. Past the mandate, I added bookmarks, notifications when an access request changes, moderated star ratings shown on the homepage, and shareable search filters with a CSV export of up to 2,000 rows. I built it between March and June 2026. The last logged release is v1.10.0 in May, and the quality checks for the summaries shipped in June.
Under the hoodTechnical detail for engineers
- Roles:
superadmin,admin_jdih,admin_anggota,walidata,registered.admin_jdihapproves through acan_approveproperty. Permission classes such asIsAdminOrAbove,IsWalidataandIsSuperAdminlive in onepermissions.py. - Access tiers
terbuka/terbatas/tertutupare enforced at the download endpoint./accesses/check/returns the right call to action without exposing the file. A Celery task expires stale access grants. - Summaries started on Gemini Flash (v1.8.0) and moved offline in v1.9.0:
pdfplumberextraction, extractive summaries withsumyandnltk, and a keyword-weighted legal-domain classifier. - Quality loop: a
RingkasanEvalRunmodel, gold-summary fields and editor, a legalese-to-plain-language glossary pass, aweekly_ai_evaltask, and anevaluate_ai_summariesbenchmark command. Superadmins can regenerate stale summaries with a Redis-backed progress bar. detect_relationsmatches citation patterns such as "mencabut Perka No. 14 Tahun 2022" and creates aRelationCandidate. Confirmed relations render at/pohon-peraturan.refresh_statistik_harianfillsStatistikHarianandStatistikDokumennightly through Celery Beat, with anActivityLogfallback.- Keycloak OIDC via
mozilla-django-oidcmaps department, NIP and name claims. The OIDC session stays server-side and mints a JWT for the frontend; public users use SimpleJWT with email and password. - Cooperation agreements (PKS and MoU) have two party names and no document number, so they use a conditional serializer and a separate slug path.
- Search uses a PostgreSQL
SearchVectorFieldwith a GIN index.sync_berita_iknimports news from the IKN portal, deduplicated by external ID. - 7 Django apps, 25 models, 90 URL patterns, 9 named Celery tasks, 36 frontend routes, 76 frontend source files, about 15,800 lines of frontend code, 100 backend and 91 frontend commits from 7 March to 24 June 2026.
Screenshots
Hiring, or building something similar?
I'm open to full-time roles and select freelance work.