Skip to content
AFM Studio
GovernmentMobile WebInternal Tool

Jejak Penanaman

Geofenced selfie check-in app for IKN tree-planting events, with plant species tracking and QR ticketing

All projects4 min read

Role

Fullstack Developer

Timeframe

Apr – Jul 2026

View liveOpen registrationSign-in required, but anyone can self-register.View on GitHub
On this page

The problem

IKN Nusantara hosts recurring tree-planting ceremonies involving both government employees and the general public. Before this system, attendance was tracked manually with paper forms and spreadsheets — no way to verify that participants were actually on-site, no central record of who attended which event, no documentation of species planted, and no photographic evidence.

Two distinct user types needed the same system: IKN government employees who authenticate via Keycloak SSO, and members of the public who register with an email address — plus walk-up participants at open events who have no account at all. Admins needed to manage events, set geofenced locations, track registrations, and export attendance reports.

The approach

Geofenced selfie check-in

Attendance submission requires both a selfie and GPS coordinates within a configurable radius (50–5000m) of the event pin. The geofence is checked twice: client-side with a Haversine calculation for immediate feedback ("you are 340m away"), and server-side in the attendance submission view to prevent API-level spoofing, using the same formula against the event's stored coordinates.

The CameraCapture component uses the browser MediaDevices API, draws the captured frame to a hidden canvas, and compresses it to max 1024px / JPEG 0.7 before upload — keeping selfies under 1 MB even on high-resolution phone cameras. iOS Safari requires getUserMedia() to be triggered by a direct user gesture, so camera activation is wired to a button click, not page load.

Every photo carries its own proof

Selfies and plant photos get a timestamp-and-GPS overlay burned directly into the canvas before upload — date and time in WITA, coordinates to 7 decimal places — and the same GPS data is embedded into the JPEG's EXIF metadata client-side via piexifjs. No server-side image processing is involved; the proof travels with the file itself.

Three ways in, one attendance model

IKN employees authenticate via Keycloak OIDC, whose claims arrive genuinely messy — names in ALL CAPS, organisational units split inconsistently across several claim fields — normalised by a custom OIDCAuthenticationBackend. Public participants register with email and get an auto-generated password via SendGrid. For open public events, a third path skips accounts entirely: an anonymous registration endpoint creates a lightweight guest user on the fly so a walk-up participant isn't blocked by the auth flow, without weakening the permission model for anyone else.

Plant species tracking

Each attendance record links to multiple flora species planted, with per-species quantity, sapling age in months, and photos — added mid-project, outside the original PRD, to support IKN's reforestation biodiversity records without breaking the existing data model. A personal "Jejak Hijau" view lets a participant see everything they've planted across every event they've attended, with a photo lightbox.

QR tickets that scale to per-institution quotas

Public events generate a unique JP-YYMMDD-NNN ticket code per registration, assigned atomically to avoid collisions, and admins scan them at the gate with the browser's camera via html5-qrcode, with audio feedback per scan result. What started as one flat quota per event grew into opt-in segmentation: an event can split its quota by government institution, each with its own nullable cap (null = unlimited) and its own list of available t-shirt sizes — registration validation resolves the participant's institution and enforces that institution's specific rules, while simpler events keep working exactly as before. Twibbon selfie overlays — branded IKN frames — composite client-side over the captured photo and download as shareable images.

Attendance that bends for real-world connectivity, without going soft

Attendance isn't fully immutable. Admins can force-create a record on a participant's behalf — including overriding the timestamp via a time picker — for the on-site connectivity failures that inevitably happen at an outdoor event, and can add plant photos to an existing record after the fact. Above the admin/participant split sits a superadmin role that manages other admins, promotes public users to employee status (locking their organisational fields so a future SSO login can't silently overwrite a manual correction), and searches, filters, and deletes across the full user base.

Outcome

Deployed to production and used in real IKN tree-planting events since mid-2026. 78 commits across roughly three months, spanning 5 Django apps, 13 models, ~90 API endpoints, and 28 frontend pages. The system handles internal events (SSO-only, no registration) and public events (open registration, per-institution quotas, QR tickets, guest walk-ins) through a single codebase, with admin dashboards breaking down attendance by directorate and department for internal reporting.

Outcomes

Backend API URL patterns
~90
Frontend screens
28
Django models across 5 apps
13
Commits over ~3 months
78

Screenshots

Beranda
Jejak Hijau
Riwayat
Event Detail
Admin Dashboard

Have a project like this?

If you need a system built with the same care — clear scope, solid execution — let's talk.

Start a project