Edutara
A rebuilt learning platform for OIKN and partner institutions, with segmented quizzes and QR-verifiable certificates
- users on the platform it replaces
- 266+
- material types in one course player
- 9
- panels for learners, institutions and admins
- 3
- from start of build to deployment-ready
- 7 days
On this page
The problem
Otorita IKN already ran a training platform for its employees and partner institutions, including Monash University, UGM and the Ministry of Finance's Learning Center. It had more than 266 registered users, and people used it for mandatory training. It was also fragile. There were no automated tests, the conventions were inconsistent, and the licences for its interface assets weren't documented, which is a legal risk for a government platform. Every change risked breaking something people depended on, and few developers could work on it safely.
The ask was a full rebuild that kept every existing feature. The audience is mixed: civil servants, private-sector staff and university students with very different comfort with technology. Institution admins run their own programs on it, and OIKN leadership needs training-hours reports for the national civil service agency.
What I built
The server checks every permission
I split the system into a backend API and a separate web frontend that talks only to that API. No business rules live in the browser. Every endpoint checks its own permissions, so a learner who tampers with the page still can't reach an admin action. The same API can later serve a mobile app or a partner system without a rewrite.
Every institution shares one database, kept apart by row
Every record has a random public ID in its links, so nobody can step through other people's records by counting. Institutions share one database. Each row belongs to an institution, and every request is scoped to the institution the user is acting for. I chose this because it is cheaper to run and easier to reason about than a database per institution, and each institution's data still stays separate.
Quiz attempts keep the questions they started with
When a learner starts a quiz, the system copies the questions onto that attempt. If an admin edits the question bank later, grades already given can't change. Quizzes are split into segments, and each segment has its own pass mark. A learner has to pass every segment, so a strong section can't hide a weak one.
Grading never blocks a learner
A submitted assignment counts as done for course progress straight away. The teacher grades it later, and can hold grades back until the institution releases them. Late work is flagged, never refused. This matches how OIKN's own approvals already work. Certificates are generated in the background the moment a learner reaches 100%. Each one has a QR code that opens a public page where anyone can check it without logging in.
A report built for sources that don't exist yet
Leadership needs training hours per employee, filtered by institution, office, directorate and position. Today Edutara is the only source of that data. OIKN plans to pull records from partner platforms later, so I built the report on a structure where every record is tagged with its source. Adding a partner later means adding a connector.
Result
Edutara is a tested build with automated checks on every change: unit tests on both sides, a coverage gate, and a full end-to-end suite that starts the whole system with sample data. The production setup is ready for OIKN's own servers. The switch from the old platform hasn't happened yet. I built it between late June and early July 2026, most of it in the first two days. During the build I redesigned the roles: one Teacher role replaced two, a platform operator tier now sits below Superadmin, and people can ask to join an institution. I also added learner testimonials, which the spec didn't ask for.
Under the hoodTechnical detail for engineers
- Django REST Framework backend and a Next.js App Router frontend over a typed API client. Every endpoint has its own DRF permission class.
- Every model exposes a UUID in URLs and responses; integer primary keys never leave the server.
- Multi-tenancy is row-level: an
institution_idforeign key plus middleware that scopes queries to the user's active institution. - The quiz engine is an explicit attempt state machine with 10 models. Questions are snapshotted per attempt; scoring is per segment with independent thresholds. Question types are multiple choice and multi-point multiple choice, with timed attempts and explanation review.
- Nine material types render in one two-panel course player: PDF, video, embedded video, rich text, image, external link, file download, quiz and assignment.
- Certificates render with WeasyPrint and
qrcodein Celery jobs. Files are served through pre-signed, time-limited URLs from S3-compatible storage. - The training-hours report (FR-28) keys on employee NIP with a
sourcefield and a connector abstraction, with cumulative and date-range modes and Excel export. - Keycloak OIDC SSO was adapted from a React, Vite and localStorage guide to App Router with httpOnly-cookie sessions.
- CI runs lint, typecheck, pytest, Vitest with Testing Library, a coverage gate, and Playwright end-to-end tests against the full Docker stack. Release images build to GHCR for a pull-and-run VM deploy.
- 12 Django apps, 43 models, 23 ViewSets, about 8,600 lines of Python and 10,900 of TypeScript, 25 backend and 32 frontend test files, 124 commits between 29 June and 5 July 2026, 109 of them in the first two days.
Hiring, or building something similar?
I'm open to full-time roles and select freelance work.