build · Sep 2026
KITO Portal Publik
Public portal. The Telegram bot, AI agent, officer dashboard, and database are team work.
- Next.js
- TypeScript
- Tailwind
- SWR
- Leaflet
- Recharts
Summary
KITO is a citizen complaint system for Palembang. Residents describe a problem to a Telegram bot in everyday language, an AI agent sorts and redacts it, officers verify and close it, and the public portal shows what happened next. This case study covers the public portal, which is the part I built.
Problem
Ombudsman RI recorded 23,596 complaints in 2025. Among reports closed in 2024, the two most common maladministration types were delayed handling at 33.86% and no service given at 30.31%, over 64% combined. All of them end at the same point: a resident spoke up and could not tell whether anyone heard. In Palembang the channels are split by agency, so a resident has to know the category and the agency before they can even report.
Approach
The portal has four jobs: a report map, a status check by tracking code, an agency speed scorecard, and category trends over time. Data is filtered at the database query level, so internal officer notes and handler names are never requested in the first place, which means they cannot leak to the public or even back to the reporter.
Outcome
A server-rendered first paint with SWR handling the interactive filters after that, a Leaflet map centered on Palembang with category-colored pins, and a trend chart built from the same data.
Honest limitations
There is no public live URL, so no Live button is offered here. The map demo on this page runs on sample data and says so. The agent and dashboard repositories are still in development and are not linked.
Detail
- Safeguards
- The agent's database account has INSERT rights only, and DELETE and SELECT attempts were tested and rejected by the database itself. Tracking codes are generated by the server, not the model.
- Field evidence
- One-time links use a random token stored as a hash, valid for one report, with an expiry. Photo GPS is compared against the reported location and a large distance raises a flag for officers.
- Pre-launch tests
- A duplicated Telegram webhook yields one row, an OpenRouter outage still stores the report, another person's tracking code is rejected, and prompt-injection reports cannot override system rules.
- Why it is built this way
- The Public Service Law and the Personal Data Protection Law drove the design: redact before storage, keep the database role tiny, and let a human make the final decision.
The map, on sample data
Report map
Loading
Loading the interactive map. The written case study above does not depend on it.
Gallery



Next project
Aid Distribution Dashboard