E-Monev IKN
A monitoring platform for Nusantara's 23-year build, tracking every unit's quarterly progress against 24 national KPIs

- of roadmap, 2022 to 2045, in one place
- 23 years
- KPIs tracked across five development stages
- 24
- report cadences, each as PDF, Word or Excel
- 5
- role levels, from super admin to guest
- 6
On this page
The problem
Indonesia is building a new capital from scratch, in five stages from 2022 to 2045. Dozens of government work units run activities at the same time, in infrastructure, governance, environment and social programs. Each has its own budget, targets and quarterly milestones.
Before E-Monev, coordinators had no single view of progress across units. Quarterly reports were put together by hand. A gap between budget and spending often surfaced only when a review was already late. The 23-year roadmap had no digital home. Nobody could say, from records, who approved or rejected a report and why. Units could also submit or change figures after the reporting period had closed.
What I built
Six roles, ranked in one list
There are six roles, from super admin down to guest, with deputy and echelon levels between them. I put them in one ranked list. Every permission check asks one question: is this person's role at least this high? Adding a new protected action takes one line. The same ranking drives both the API and which pages the browser shows.
Quarterly reports move through fixed steps
Each activity gets a quarterly progress report with planned and actual figures and evidence files. A report moves from draft to submitted, then to approved or sent back for revision. Only allowed moves are possible, and each one records who made it, when and why. A report can only be edited while it's a draft, so the page locks it once it's submitted. Operational plans once had their own approval step. I removed it, because the real approval happens at the quarterly report, and two review queues meant twice the work.
Deadlines the server enforces
Administrators set when reporting and planning windows open and close, and can extend a deadline for one unit. The server checks the window on every write. Late changes are refused even if someone calls the system directly. The banners on the dashboard only tell people what the server already enforces.
Sign-in that finds your unit for you
Staff sign in through IKN's single sign-on. It sends job titles as plain text, like "Direktur Data dan Kecerdasan Buatan", and it couldn't be changed to send unit IDs. I wrote a matcher that cleans up the title and scores word overlap to find the right work unit on every login. Nobody has to assign people to units by hand.
Problems and imports with structure
Early on, problems with an activity went into one free-text notes field. I gave them their own records. An activity can have many issues, each with a status, the units helping, and a trail of follow-up actions. Bulk imports got the same care: an admin uploads a spreadsheet, sees every error without anything being saved, then saves it all at once.
Result
E-Monev covers the full IKN monitoring framework: 24 KPIs across five stages, eight principles and six aspects, over the 23-year roadmap. A four-tab dashboard gives each role its own view of the same data, with an executive summary, analytics, a KPI relationship graph and a map of every geolocated activity. Reports come out monthly, quarterly, by semester, yearly and at the end of each stage, as PDF, Word or Excel. The backend is in production, and the frontend is packaged to deploy the same way. I built both sides between May and July 2026, and the scope grew well past the original spec.
Under the hoodTechnical detail for engineers
- Roles
super_admin, admin, deputi_pp, eselon_1, eselon_2, guestsit in aROLE_HIERARCHYlist;User.has_min_role()compares positions. Permission classes such asIsSuperAdminandCanApproveROwrap that one comparison. TriwulanProgresscarries aReviewStatus(Draft, Submitted, Need Revision, Approved) with aVALID_TRANSITIONSmap.transition_to()validates the move and writes aReviewHistoryrow.is_editableis true only in Draft.ReportingWindow,PerencanaanWindowandRencanaOperasionalWindow, plusReportingWindowExtensionfor per-unit overrides. Checks inreporting_window/services.pyraiseValidationErrorfrom serializers and views.- Keycloak SSO: the backend exchanges the auth code server-to-server and issues its own SimpleJWT pair, so the frontend needs no OIDC library.
apps/users/oidc.pystrips diacritics, maps title prefixes to unit prefixes and scores word overlap to resolveUnitOrganisasiandUnitKerja. - Master data moved from bigint to UUID primary keys with an in-place forward migration for deployed databases, then a cleanup of migration-history inconsistencies.
IsuandTindakLanjutmodels with aunit_pembantumany-to-many.BulkMixinexposesbulk_validate(dry run) andbulk_commit(atomic) with foreign-key resolution per category.AuditMixinaddscreated_by,updated_byand timestamps across models;AuditModelViewSetMixinfills them in.- The frontend
MasterDataContextstarted on localStorage, moved to the API behind the same interface, then became lazy withuseMasterCategories(). - Leaflet maps load through
next/dynamicwithssr: false. The KPI graph uses React Flow. Reports use WeasyPrint, python-docx and openpyxl. - CI publishes the backend image to GHCR on every push to main behind a
pip-auditgate. - 9 Django apps, about 29 models, 30 frontend routes, 225 frontend source files, about 9,760 lines of Python and 29,300 of TypeScript, 82 backend and 145 frontend commits since 20 May 2026.
Screenshots
Hiring, or building something similar?
I'm open to full-time roles and select freelance work.