[{"data":1,"prerenderedAt":2259},["ShallowReactive",2],{"project-ai-todo-en":3,"all-projects-engineering-design-en":253},{"id":4,"title":5,"architecture":6,"body":31,"category":211,"company":212,"contribution":213,"cover":215,"description":216,"draft":217,"extension":218,"featured":217,"links":219,"meta":223,"metrics":224,"navigation":234,"order":235,"path":236,"role":237,"seo":238,"stem":239,"technologies":240,"timeline":249,"type":250,"year":251,"__hash__":252},"projects_en\u002Fprojects\u002Fai-todo.md","AI Todo",[7,11,15,19,23,27],{"id":8,"label":9,"detail":10},"clients","PWA & Mac menu bar app","Vue 3 PWA for phone, tablet and PC (Web Push), plus a native AppKit menu bar app with a badge, quick check-off, a chat panel (⌥⌘T) and local notifications.",{"id":12,"label":13,"detail":14},"api","Go HTTP API","Session cookies (HttpOnly, Secure, SameSite=Strict), a required CSRF header, login rate limits, strict CSP. Every query is scoped to the user.",{"id":16,"label":17,"detail":18},"assistant","Assistant","The model returns a JSON action plan. Only whitelisted operations are accepted; deletes and bulk changes wait for a confirm button, and every batch can be undone.",{"id":20,"label":21,"detail":22},"core","Core","The same validation as the manual forms. The AI never writes to the database directly.",{"id":24,"label":25,"detail":26},"scheduler","Scheduler","Reminder times are computed by the server, not the AI — once, daily, weekly, monthly, yearly, or every N minutes inside a time window.",{"id":28,"label":29,"detail":30},"ai","AI providers","kenari, Agnes AI and OpenRouter free models with fallback in admin-defined order. Keys live only in the server environment; hosts are allowlisted.",{"type":32,"value":33,"toc":199},"minimark",[34,39,48,52,55,59,118,122,125,129,165,169,173,177,180,184,188,195],[35,36,38],"h2",{"id":37},"problem","Problem",[40,41,42,43,47],"p",{},"Todo apps make you fill in forms; chat assistants forget what you told them yesterday and can't be trusted to touch your data. I wanted to type ",[44,45,46],"em",{},"\"tomorrow at 9 remind me to call the workshop, and mark buy water done\""," and have it happen — on my phone and on my Mac — without giving an AI free rein over a database.",[35,49,51],{"id":50},"context","Context",[40,53,54],{},"A personal tool, built to run cheaply on my own VPS: free AI models only, one small server, and notifications on every device I use. Everything the chat can do must also be possible by hand, so the app stays useful when the AI is down or wrong.",[35,56,58],{"id":57},"solution","Solution",[60,61,62,86,92,98,112],"ul",{},[63,64,65,69,70,73,74,78,79,78,82,85],"li",{},[66,67,68],"strong",{},"Chat as a shortcut",": add, edit, complete, delete, search and summarise todos and reminders from one chat box. Actions show up as cards with an ",[66,71,72],{},"Undo"," button; deletes and bulk changes ask for confirmation first. Slash commands (",[75,76,77],"code",{},"\u002Ftodo",", ",[75,80,81],{},"\u002Fhari-ini",[75,83,84],{},"\u002Fundo",") work without any AI at all.",[63,87,88,91],{},[66,89,90],{},"Manual is complete",": todo lists with Today \u002F Upcoming \u002F No date \u002F Done tabs, search, lists, priority, notes, and reminders that can be one-off or recurring with an end date, a count, snooze and pause.",[63,93,94,97],{},[66,95,96],{},"An assistant that remembers",": a profile and notes (inspired by Hermes Agent) are sent with every message and can be reviewed, edited and exported. Memory is scanned before saving and rejects passwords, PINs, tokens, card numbers and prompt-injection patterns.",[63,99,100,103,104,107,108,111],{},[66,101,102],{},"Notifications everywhere",": Web Push for the PWA, native notifications with ",[44,105,106],{},"Done"," \u002F ",[44,109,110],{},"Snooze 10 min"," on the Mac, plus a morning summary and overdue nudges.",[63,113,114,117],{},[66,115,116],{},"Separate admin mode",": AI model catalog (test, enable, fallback order), assistant persona and limits, AI call log and system log — with no endpoint that can read another user's todos, chats or memory.",[35,119,121],{"id":120},"architecture","Architecture",[123,124],"architecture-explorer",{":nodes":120},[35,126,128],{"id":127},"technical-challenges","Technical challenges",[60,130,131,137,143,149,155],{},[63,132,133,136],{},[66,134,135],{},"Keeping the AI out of the database."," The model can only propose a JSON plan. The server checks each operation against a whitelist, validates its shape, runs it through the same core functions as the forms inside a transaction, and records an undo entry.",[63,138,139,142],{},[66,140,141],{},"Free models are unreliable."," The client tolerates odd replies, falls back across providers in order, and logs every outgoing call so the admin can see which model failed and why.",[63,144,145,148],{},[66,146,147],{},"Recurring schedules are easy to get wrong."," The scheduler — not the AI — computes every next occurrence in the user's time zone and stores times as UTC, with tests for windows, month ends, end dates and counts.",[63,150,151,154],{},[66,152,153],{},"A Mac app without a Mac in CI."," The HTTP client is Foundation-only, so it is tested on Linux against the real Go server; the AppKit part is compiled and released by a macOS GitHub Actions workflow.",[63,156,157,160,161,164],{},[66,158,159],{},"Deploys that can't brick the server."," Each merge to ",[75,162,163],{},"main"," backs up the database, rebuilds the container, runs a health check and rolls back automatically if it fails.",[35,166,168],{"id":167},"impact","Impact",[170,171],"metric-grid",{":metrics":172},"metrics",[35,174,176],{"id":175},"lessons-learned","Lessons learned",[40,178,179],{},"Treat the language model as a user with a very fast keyboard, not as part of the backend: give it the same forms everyone else gets, make dangerous actions need a human click, and make everything undoable. That one rule kept the rest of the design simple.",[35,181,183],{"id":182},"snapshots","Snapshots",[185,186],"gallery",{":images":187},"[{\"src\":\"\u002Fimages\u002Fwork\u002Fai-todo\u002Fchat.webp\",\"alt\":\"Assistant chat with an action card and Undo\"},{\"src\":\"\u002Fimages\u002Fwork\u002Fai-todo\u002Ftodo-dark.webp\",\"alt\":\"Today's todos in dark mode\"},{\"src\":\"\u002Fimages\u002Fwork\u002Fai-todo\u002Freminders-dark.webp\",\"alt\":\"Recurring reminders computed by the server\"},{\"src\":\"\u002Fimages\u002Fwork\u002Fai-todo\u002Fmemory.webp\",\"alt\":\"AI memory — profile and assistant notes\"}]",[40,189,190],{},[191,192],"img",{"alt":193,"src":194},"The PWA on a phone: assistant, todo (swipe right to complete, left to edit or delete) and reminders","\u002Fimages\u002Fwork\u002Fai-todo\u002Fphones.webp",[185,196],{":images":197,"fit":198},"[{\"src\":\"\u002Fimages\u002Fwork\u002Fai-todo\u002Fmac-todo.webp\",\"alt\":\"Mac menu bar app — Todo tab\",\"caption\":\"Mac menu bar app, Todo tab: quick add, Today \u002F All \u002F Done, check off with one click. Illustration based on the app's AppKit layout.\"},{\"src\":\"\u002Fimages\u002Fwork\u002Fai-todo\u002Fmac-chat-dark.webp\",\"alt\":\"Mac menu bar app — Chat tab in dark mode\",\"caption\":\"Chat tab (⌥⌘T) in dark mode: actions appear as a card with Undo. Illustration based on the app's AppKit layout.\"}]","contain",{"title":200,"searchDepth":201,"depth":201,"links":202},"",2,[203,204,205,206,207,208,209,210],{"id":37,"depth":201,"text":38},{"id":50,"depth":201,"text":51},{"id":57,"depth":201,"text":58},{"id":120,"depth":201,"text":121},{"id":127,"depth":201,"text":128},{"id":167,"depth":201,"text":168},{"id":175,"depth":201,"text":176},{"id":182,"depth":201,"text":183},"Product · AI assistant","Personal project",{"mine":214},"Sole developer — product spec, Go server, Vue PWA, Swift menu bar app, CI\u002FCD and deployment.","\u002Fimages\u002Fwork\u002Fai-todo\u002Ftodo.webp","A todo list and reminder app you can run by chatting with an AI or by hand — one Go binary with SQLite, an installable PWA and a macOS menu bar app, where the AI only proposes actions and the server validates them.",false,"md",[220],{"label":221,"url":222},"GitHub","https:\u002F\u002Fgithub.com\u002Fkikiraihan\u002Fmac-os-ai-todo",{},[225,228,231],{"value":226,"label":227},"3","free AI providers with fallback",{"value":229,"label":230},"6","reminder schedule types",{"value":232,"label":233},"1","binary + one SQLite file",true,11,"\u002Fprojects\u002Fai-todo","Full-stack Developer",{"title":5,"description":216},"projects\u002Fai-todo",[241,242,243,244,245,246,247,248],"Go","SQLite","Vue 3","PWA","Web Push","Swift","AppKit","Docker","Oct 2026 — Nov 2026","engineering",2026,"dL33JjBApHYsF3qjqtdvg3bWPRdFjNZTVXD-sBRYsN0",[254,410,557,824,933,1057,1190,1251,1420,1469,1564,1688,1841,1928,2022,2094,2210],{"id":255,"title":256,"architecture":257,"body":281,"category":373,"company":374,"contribution":375,"cover":378,"description":379,"draft":217,"extension":218,"featured":234,"links":380,"meta":385,"metrics":386,"navigation":234,"order":396,"path":397,"role":398,"seo":399,"stem":400,"technologies":401,"timeline":407,"type":250,"year":408,"__hash__":409},"projects_en\u002Fprojects\u002Fvektorpedia.md","VektorPedia",[258,262,266,270,274,277],{"id":259,"label":260,"detail":261},"sources","GloBI · Wikidata · DBpedia · NCBITaxon","Four public knowledge graphs describing species, taxonomy and biotic interactions.",{"id":263,"label":264,"detail":265},"ingest","Ingestion & alignment","Entities from each source are ingested and aligned into one biodiversity knowledge graph.",{"id":267,"label":268,"detail":269},"graph","Biodiversity knowledge graph","Insects, viruses and plants connected by typed interaction edges.",{"id":271,"label":272,"detail":273},"analysis","Network analysis & scoring","Graph metrics score how likely an insect is to act as a vector for a plant virus.",{"id":12,"label":275,"detail":276},"Python web server","Handles queries and data processing for the search engine.",{"id":278,"label":279,"detail":280},"client","Vue client","Search UI for researchers to explore candidate vectors and their evidence.",{"type":32,"value":282,"toc":363},[283,285,295,297,300,302,308,310,312,314,334,336,338,353,355,358,360],[35,284,38],{"id":37},[40,286,287,288,291,292,294],{},"Plant viruses spread through insects, but the knowledge of ",[44,289,290],{},"which"," insect carries ",[44,293,290],{}," virus is scattered across many biodiversity databases. Researchers and plant-disease practitioners had no single place to ask: \"which insects are likely vectors for this virus?\"",[35,296,51],{"id":50},[40,298,299],{},"This was my master's thesis at IPB University. The data already existed publicly — in Global Biotic Interactions (GloBI), Wikidata, DBpedia and the NCBI Taxonomy ontology — but in different shapes, identifiers and levels of completeness.",[35,301,58],{"id":57},[40,303,304,305,307],{},"I built ",[66,306,256],{},", a search engine backed by an integrated biodiversity knowledge graph. Data from the four sources was ingested and aligned into one graph that captures relationships between insects, viruses and plants. Network analysis on that graph surfaces and scores candidate insect vectors.",[35,309,121],{"id":120},[123,311],{":nodes":120},[35,313,128],{"id":127},[60,315,316,322,328],{},[63,317,318,321],{},[66,319,320],{},"Heterogeneous sources"," — each knowledge graph uses its own identifiers and vocabulary, so entities had to be aligned before any analysis made sense.",[63,323,324,327],{},[66,325,326],{},"Signal from structure"," — interactions are sparse; network analysis was used to infer likely vectors from how species are connected, not just from direct records.",[63,329,330,333],{},[66,331,332],{},"Research to product"," — turning a research pipeline into a usable search application within about three months.",[35,335,168],{"id":167},[170,337],{":metrics":172},[40,339,340,341,344,345,352],{},"The work was published in a Scopus-indexed journal (",[44,342,343],{},"JISEBI",", 2024) and deployed at ",[346,347,351],"a",{"href":348,"rel":349},"https:\u002F\u002Fvektorpedia.ipb.ac.id\u002F",[350],"nofollow","vektorpedia.ipb.ac.id",".",[35,354,176],{"id":175},[40,356,357],{},"Knowledge graphs are powerful precisely because they carry context — but most of the effort is in the unglamorous alignment work. A good search experience on top is what makes the research usable by people outside the lab.",[35,359,183],{"id":182},[185,361],{":images":362},"[{\"src\":\"\u002Fimages\u002Fwork\u002Fvektorpedia\u002F1.jpeg\",\"alt\":\"Summary of the idea\"},{\"src\":\"\u002Fimages\u002Fwork\u002Fvektorpedia\u002F2.jpeg\",\"alt\":\"Research stages\"},{\"src\":\"\u002Fimages\u002Fwork\u002Fvektorpedia\u002F3.jpeg\",\"alt\":\"Interaction graph\"},{\"src\":\"\u002Fimages\u002Fwork\u002Fvektorpedia\u002F4.jpeg\",\"alt\":\"Embedded taxon\"},{\"src\":\"\u002Fimages\u002Fwork\u002Fvektorpedia\u002F5.jpg\",\"alt\":\"Insect vector scoring\"},{\"src\":\"\u002Fimages\u002Fwork\u002Fvektorpedia\u002F6.jpg\",\"alt\":\"Detail information page\"}]",{"title":200,"searchDepth":201,"depth":201,"links":364},[365,366,367,368,369,370,371,372],{"id":37,"depth":201,"text":38},{"id":50,"depth":201,"text":51},{"id":57,"depth":201,"text":58},{"id":120,"depth":201,"text":121},{"id":127,"depth":201,"text":128},{"id":167,"depth":201,"text":168},{"id":175,"depth":201,"text":176},{"id":182,"depth":201,"text":183},"AI · Knowledge Graph","IPB University",{"team":376,"mine":377},"Research direction and supervision came from my thesis supervisors.","Data ingestion, knowledge-graph integration, network analysis, and the full search application (backend + frontend).","\u002Fimages\u002Fwork\u002Fvektorpedia\u002F6.jpg","A search engine that finds insect vectors of plant viruses by integrating four public knowledge graphs and running network analysis on top.",[381,382],{"label":351,"url":348},{"label":383,"url":384},"Published paper","https:\u002F\u002Fe-journal.unair.ac.id\u002FJISEBI\u002Farticle\u002Fview\u002F50015",{},[387,390,393],{"value":388,"label":389},"4","public knowledge graphs integrated",{"value":391,"label":392},"3 mo","from design to deployed app",{"value":394,"label":395},"Scopus","indexed publication",1,"\u002Fprojects\u002Fvektorpedia","Researcher & Engineer (Master thesis)",{"title":256,"description":379},"projects\u002Fvektorpedia",[402,403,404,405,406],"Python","Vue","SPARQL","Knowledge Graph","Network Analysis","Aug 2022 — Dec 2023",2023,"dOjwgSq9YCLxnoPpw9MnHTU_aMr9Dnhrfc8MfCtxB9w",{"id":411,"title":412,"architecture":413,"body":433,"category":525,"company":526,"contribution":527,"cover":530,"description":531,"draft":217,"extension":218,"featured":234,"links":532,"meta":536,"metrics":537,"navigation":234,"order":201,"path":546,"role":547,"seo":548,"stem":549,"technologies":550,"timeline":554,"type":250,"year":555,"__hash__":556},"projects_en\u002Fprojects\u002Fmakassar-raya-motor.md","Spatial Sales Intelligence",[414,418,422,425,429],{"id":415,"label":416,"detail":417},"data","Sales data + BPS indicators","Dealer sales records combined with GDP, per-capita income and population data from Statistics Indonesia (BPS).",{"id":419,"label":420,"detail":421},"geo","GeoJSON boundaries","Province, district and sub-district boundaries prepared with the spatial mapping team.",{"id":12,"label":423,"detail":424},"FastAPI spatial service","Processes spatial data and powers the mapping features.",{"id":426,"label":427,"detail":428},"viz","Plotly dashboards","Interactive maps and charts per province, district and sub-district.",{"id":430,"label":431,"detail":432},"app","Laravel Livewire web app","Data management, imports and the embedded dashboards in one place.",{"type":32,"value":434,"toc":515},[435,437,440,442,445,447,477,479,481,483,494,496,498,501,503,510,512],[35,436,38],{"id":37},[40,438,439],{},"PT. Makassar Raya Motor runs 10 Daihatsu branches across South, Central and Southeast Sulawesi. Sales decisions were made without a clear geographic view of where demand was strong, weak, or untapped.",[35,441,51],{"id":50},[40,443,444],{},"Sales data existed, but not tied to geography or to socio-economic context. The analysis had to work at multiple levels — province, district, sub-district and village — and be usable by non-technical stakeholders.",[35,446,58],{"id":57},[60,448,449,455,461,467],{},[63,450,451,454],{},[66,452,453],{},"Spatial analysis"," of sales across 3 provinces, 54 districts, 709 sub-districts and 7,394 villages.",[63,456,457,460],{},[66,458,459],{},"Maps with context"," — combined with GDP, per-capita income and population indicators from BPS, designed together with urban-planning experts.",[63,462,463,466],{},[66,464,465],{},"Interactive dashboards"," built with Python Plotly.",[63,468,469,472,473,476],{},[66,470,471],{},"A full-stack web app"," (Laravel Livewire) for data management, imports and the embedded dashboards, backed by a ",[66,474,475],{},"FastAPI"," service for spatial processing.",[35,478,121],{"id":120},[123,480],{":nodes":120},[35,482,128],{"id":127},[60,484,485,488,491],{},[63,486,487],{},"Absorbing and cleaning GeoJSON for three provinces at several administrative levels.",[63,489,490],{},"Keeping maps responsive while rendering hundreds of sub-district polygons.",[63,492,493],{},"Joining sales records to administrative areas consistently.",[35,495,168],{"id":167},[170,497],{":metrics":172},[40,499,500],{},"Stakeholders could explore sales performance next to socio-economic indicators at a glance, instead of reading spreadsheets per branch.",[35,502,176],{"id":175},[40,504,505,506,509],{},"The value of a dashboard is in the questions it lets people ask. Pairing sales with public socio-economic data turned \"where did we sell?\" into \"where ",[44,507,508],{},"should"," we sell?\".",[35,511,183],{"id":182},[185,513],{":images":514},"[{\"src\":\"\u002Fimages\u002Fwork\u002Fmakassar-raya-motor\u002Fmrm1.jpeg\",\"alt\":\"Map analysis\"},{\"src\":\"\u002Fimages\u002Fwork\u002Fmakassar-raya-motor\u002Fmrm3.jpeg\",\"alt\":\"Dashboard analysis\"},{\"src\":\"\u002Fimages\u002Fwork\u002Fmakassar-raya-motor\u002Fmrm2.jpeg\",\"alt\":\"Data management\"},{\"src\":\"\u002Fimages\u002Fwork\u002Fmakassar-raya-motor\u002Fmrm4.jpeg\",\"alt\":\"Data import feature\"}]",{"title":200,"searchDepth":201,"depth":201,"links":516},[517,518,519,520,521,522,523,524],{"id":37,"depth":201,"text":38},{"id":50,"depth":201,"text":51},{"id":57,"depth":201,"text":58},{"id":120,"depth":201,"text":121},{"id":127,"depth":201,"text":128},{"id":167,"depth":201,"text":168},{"id":175,"depth":201,"text":176},{"id":182,"depth":201,"text":183},"Data · Geo-web","PT. Makassar Raya Motor",{"team":528,"mine":529},"Map design was done together with urban-planning experts on the spatial mapping team.","Spatial analysis, the Plotly dashboards, the FastAPI backend and the Livewire web application.","\u002Fimages\u002Fwork\u002Fmakassar-raya-motor\u002Fmrm1.jpeg","Spatial analysis and an interactive dashboard that maps sales performance across 3 provinces down to 7,394 villages for a Daihatsu dealer group.",[533],{"label":534,"url":535},"Client profile","https:\u002F\u002Fdaihatsumrm.co.id\u002F",{},[538,540,543],{"value":226,"label":539},"provinces analysed",{"value":541,"label":542},"709","sub-districts mapped",{"value":544,"label":545},"7,394","villages covered","\u002Fprojects\u002Fmakassar-raya-motor","Software Engineer & Data Analyst (Contract)",{"title":412,"description":531},"projects\u002Fmakassar-raya-motor",[402,475,551,552,553],"Plotly","Laravel Livewire","GeoJSON","Oct 2023 — Jun 2024",2024,"ZcObAZoYXYFbONe2leOXmdFqB5pdgvaPioYN6Ug5Y1o",{"id":558,"title":559,"architecture":560,"body":575,"category":794,"company":795,"contribution":796,"cover":798,"description":799,"draft":217,"extension":218,"featured":234,"links":800,"meta":804,"metrics":805,"navigation":234,"order":814,"path":815,"role":816,"seo":817,"stem":818,"technologies":819,"timeline":821,"type":250,"year":822,"__hash__":823},"projects_en\u002Fprojects\u002Ftimemarket.md","TimeMarket",[561,564,568,571],{"id":278,"label":562,"detail":563},"Mobile-first PWA","Installable from Chrome so it behaves like a native Android app.",{"id":565,"label":566,"detail":567},"ui","Livewire components","Interactive UI without a separate SPA, which kept development fast.",{"id":430,"label":569,"detail":570},"Laravel application","Programmes (proker), jobs, delegation rules and the role\u002Fpermission model.",{"id":572,"label":573,"detail":574},"db","MySQL","Employees, programmes, jobs and workload history.",{"type":32,"value":576,"toc":785},[577,579,582,584,605,607,632,639,641,643,645,652,773,775,777,780,782],[35,578,38],{"id":37},[40,580,581],{},"As part of Bank Indonesia's internal innovation programme, the Gorontalo office needed a way to delegate work accurately, monitor it, and keep each employee's workload within a reasonable limit.",[35,583,51],{"id":50},[40,585,586,587,78,590,78,593,596,597,600,601,604],{},"It had to be usable from anywhere and easy for every employee — from staff to the head of office. Four roles were involved: ",[66,588,589],{},"Employee",[66,591,592],{},"Team Leader (Chief)",[66,594,595],{},"Head of Office (KPw)"," and ",[66,598,599],{},"Admin",", each with different rights over programmes (",[44,602,603],{},"proker",") and jobs.",[35,606,58],{"id":57},[60,608,609,616,622,629],{},[63,610,611,612,615],{},"An interactive UI with ",[66,613,614],{},"Livewire"," to keep development fast.",[63,617,618,621],{},[66,619,620],{},"Mobile-first"," design so it works equally well on desktop and phones.",[63,623,624,625,628],{},"A ",[66,626,627],{},"semi-PWA"," mode: with the right metadata, the app can be installed from Chrome and opened like a native Android app.",[63,630,631],{},"A user manual for rollout.",[40,633,634],{},[635,636],"video",{"src":637,"controls":234,"muted":234,"playsInline":234,"preload":638},"\u002Fimages\u002Fwork\u002Ftimemarket\u002Ftimemarket_homescreen.webm","none",[35,640,121],{"id":120},[123,642],{":nodes":120},[35,644,128],{"id":127},[40,646,647,648,651],{},"The permission model was the core of the product: who can create, edit, transfer or complete a job depends on the role ",[44,649,650],{},"and"," on whether the user leads that programme.",[653,654,655,675],"table",{},[656,657,658],"thead",{},[659,660,661,665,667,670,673],"tr",{},[662,663,664],"th",{},"Feature",[662,666,589],{},[662,668,669],{},"Chief",[662,671,672],{},"Head of Office",[662,674,599],{},[676,677,678,693,707,721,734,747,760],"tbody",{},[659,679,680,684,687,689,691],{},[681,682,683],"td",{},"View programmes & jobs",[681,685,686],{},"Yes",[681,688,686],{},[681,690,686],{},[681,692,686],{},[659,694,695,698,701,703,705],{},[681,696,697],{},"Add programme",[681,699,700],{},"—",[681,702,686],{},[681,704,700],{},[681,706,700],{},[659,708,709,712,715,717,719],{},[681,710,711],{},"Edit programme",[681,713,714],{},"If programme lead",[681,716,686],{},[681,718,700],{},[681,720,686],{},[659,722,723,726,728,730,732],{},[681,724,725],{},"Add \u002F edit \u002F delete job",[681,727,714],{},[681,729,714],{},[681,731,700],{},[681,733,700],{},[659,735,736,739,741,743,745],{},[681,737,738],{},"Transfer job to others",[681,740,714],{},[681,742,714],{},[681,744,700],{},[681,746,700],{},[659,748,749,752,754,756,758],{},[681,750,751],{},"Mark job completed",[681,753,686],{},[681,755,700],{},[681,757,700],{},[681,759,700],{},[659,761,762,765,767,769,771],{},[681,763,764],{},"Main calendar",[681,766,686],{},[681,768,686],{},[681,770,686],{},[681,772,700],{},[35,774,168],{"id":167},[170,776],{":metrics":172},[40,778,779],{},"The contract was extended for a second version, delivered in 3 months, followed by 6 months of maintenance.",[35,781,176],{"id":175},[40,783,784],{},"For internal tools, adoption beats features. Making it installable on the phones people already carried did more for usage than any single feature.",{"title":200,"searchDepth":201,"depth":201,"links":786},[787,788,789,790,791,792,793],{"id":37,"depth":201,"text":38},{"id":50,"depth":201,"text":51},{"id":57,"depth":201,"text":58},{"id":120,"depth":201,"text":121},{"id":127,"depth":201,"text":128},{"id":167,"depth":201,"text":168},{"id":175,"depth":201,"text":176},"Product · Full-stack","Bank Indonesia — Gorontalo Office",{"mine":797},"Full-stack development of v1 and v2, the PWA mode, and the user manual.","\u002Fimages\u002Fwork\u002Ftimemarket\u002Ftimemarket.png","A workload-management PWA for Bank Indonesia's Gorontalo office that balances how work is delegated across employees.",[801],{"label":802,"url":803},"timemarket.masuk.id","https:\u002F\u002Ftimemarket.masuk.id",{},[806,808,811],{"value":388,"label":807},"user roles with distinct permissions",{"value":809,"label":810},"6 mo","full-stack build of v1",{"value":812,"label":813},"v2","contract extended for a second version",3,"\u002Fprojects\u002Ftimemarket","Web Developer (Contract)",{"title":559,"description":799},"projects\u002Ftimemarket",[820,614,244,573],"Laravel","May 2021 — Aug 2022",2021,"gTpYtl4U0_DuxNKaXjo1rbcMIKZho90K9C3XVCvpukM",{"id":825,"title":826,"architecture":827,"body":841,"category":905,"company":826,"contribution":906,"cover":909,"description":910,"draft":217,"extension":218,"featured":234,"links":911,"meta":915,"metrics":916,"navigation":234,"order":923,"path":924,"role":925,"seo":926,"stem":927,"technologies":928,"timeline":931,"type":250,"year":408,"__hash__":932},"projects_en\u002Fprojects\u002Fcontag.md","Contag School",[828,831,834,838],{"id":8,"label":829,"detail":830},"Back office & app","Admin back office and the end-user application.",{"id":12,"label":832,"detail":833},"NestJS API","Modular services with dependency injection, one module per domain.",{"id":835,"label":836,"detail":837},"domain","Academic domain modules","20+ modules covering academic-affairs workflows.",{"id":572,"label":839,"detail":840},"Database","Persistent academic data.",{"type":32,"value":842,"toc":896},[843,845,848,850,864,866,868,870,882,884,886,888,891,893],[35,844,38],{"id":37},[40,846,847],{},"Contag School builds SaaS products for university academic-affairs management. They needed a robust backend so their back office and apps could share data and automate workflows.",[35,849,58],{"id":57},[40,851,852,853,856,857,860,861,352],{},"I developed ",[66,854,855],{},"more than 20 API modules"," on ",[66,858,859],{},"NestJS",", tailored to Contag's academic workflows, and kept a steady delivery rhythm with ",[66,862,863],{},"800+ commits",[35,865,121],{"id":120},[123,867],{":nodes":120},[35,869,128],{"id":127},[60,871,872,875],{},[63,873,874],{},"Keeping a growing number of modules consistent and independent — NestJS modules + dependency injection helped enforce boundaries.",[63,876,877,878,881],{},"Applying ",[66,879,880],{},"SOLID"," principles so new features extend the system instead of rewriting it.",[35,883,168],{"id":167},[170,885],{":metrics":172},[35,887,176],{"id":175},[40,889,890],{},"With many modules, conventions matter more than cleverness. Clear naming and consistent structure made the codebase easy for the rest of the team to pick up.",[35,892,183],{"id":182},[185,894],{":images":895},"[{\"src\":\"\u002Fimages\u002Fwork\u002Fcontag\u002Fc1.jpeg\",\"alt\":\"Back office\"},{\"src\":\"\u002Fimages\u002Fwork\u002Fcontag\u002Fc2.jpeg\",\"alt\":\"App\"}]",{"title":200,"searchDepth":201,"depth":201,"links":897},[898,899,900,901,902,903,904],{"id":37,"depth":201,"text":38},{"id":57,"depth":201,"text":58},{"id":120,"depth":201,"text":121},{"id":127,"depth":201,"text":128},{"id":167,"depth":201,"text":168},{"id":175,"depth":201,"text":176},{"id":182,"depth":201,"text":183},"Backend · SaaS",{"team":907,"mine":908},"Product direction and the client apps were owned by the Contag team.","Backend API modules, following SOLID and clean-code practices.","\u002Fimages\u002Fwork\u002Fcontag\u002Fc2.jpeg","Backend API modules for a SaaS platform that manages university academic affairs.",[912],{"label":913,"url":914},"contag.id","https:\u002F\u002Fcontag.id\u002F",{},[917,920],{"value":918,"label":919},"20+","API modules delivered",{"value":921,"label":922},"800+","commits",4,"\u002Fprojects\u002Fcontag","Backend Engineer",{"title":826,"description":910},"projects\u002Fcontag",[859,929,930],"Node.js","TypeScript","Mar 2023 — Oct 2023","R-rSIFQXF7d6hfmK21XBA5IYZCx2_TCzFJh1L6Zit-Q",{"id":934,"title":935,"architecture":936,"body":950,"category":1026,"company":935,"contribution":1027,"cover":1030,"description":1031,"draft":217,"extension":218,"featured":234,"links":1032,"meta":1039,"metrics":1040,"navigation":234,"order":1047,"path":1048,"role":1049,"seo":1050,"stem":1051,"technologies":1052,"timeline":1054,"type":250,"year":1055,"__hash__":1056},"projects_en\u002Fprojects\u002Fdigimosque.md","Digimosque",[937,941,944,946],{"id":938,"label":939,"detail":940},"android","Android app","Mosque discovery, donations, takmir features.",{"id":12,"label":942,"detail":943},"Laravel API","Includes the nearest-mosque search algorithm.",{"id":572,"label":839,"detail":945},"Redesigned to support new features while keeping legacy data.",{"id":947,"label":948,"detail":949},"admin","Livewire admin panel","Mosque data, IoT device access, takmir verification.",{"type":32,"value":951,"toc":1017},[952,954,957,959,962,964,989,991,993,995,997,1000,1002,1005,1007,1010],[35,953,38],{"id":37},[40,955,956],{},"Digimosque is a digital mosque platform: find mosques nearby, donate to religious activities, manage mosque cash \u002F infaq \u002F qurban, and connect IoT devices (displays, AC, prayer times). The Android prototype needed a real API, and administrators needed a web panel.",[35,958,51],{"id":50},[40,960,961],{},"The existing data had to be kept, so we reverse-engineered the old database and adjusted it for new features. The deadline was close.",[35,963,58],{"id":57},[60,965,966,973,980],{},[63,967,968,969,972],{},"Advised on the ",[66,970,971],{},"database redesign"," with the product manager.",[63,974,975,976,979],{},"Built the ",[66,977,978],{},"nearest-mosque search"," API and several other endpoints.",[63,981,975,982,985,986,988],{},[66,983,984],{},"entire admin panel"," with ",[66,987,614],{}," — reusable components made it possible to ship 15 modules in under two months.",[35,990,121],{"id":120},[123,992],{":nodes":120},[35,994,168],{"id":167},[170,996],{":metrics":172},[40,998,999],{},"The app is available on the Play Store.",[35,1001,176],{"id":175},[40,1003,1004],{},"Picking a tool for the deadline, not for the résumé: Livewire let me reuse components and move fast without building a separate SPA.",[35,1006,183],{"id":182},[185,1008],{":images":1009},"[{\"src\":\"\u002Fimages\u002Fwork\u002Fdigimosque\u002Fdigi1.png\",\"alt\":\"Admin panel\"},{\"src\":\"\u002Fimages\u002Fwork\u002Fdigimosque\u002Fdigi2.png\",\"alt\":\"Admin panel\"},{\"src\":\"\u002Fimages\u002Fwork\u002Fdigimosque\u002Fdigi3.png\",\"alt\":\"Admin panel\"},{\"src\":\"\u002Fimages\u002Fwork\u002Fdigimosque\u002Fdigi4.png\",\"alt\":\"Admin panel\"}]",[1011,1012],"iframe",{"src":1013,"title":1014,"loading":1015,"allow":1016,"allowFullScreen":234},"https:\u002F\u002Fwww.youtube-nocookie.com\u002Fembed\u002FuFxaXUciovo","DigiMosque Box & DigiMosque Mobile Apps","lazy","accelerometer; clipboard-write; encrypted-media; gyroscope; picture-in-picture",{"title":200,"searchDepth":201,"depth":201,"links":1018},[1019,1020,1021,1022,1023,1024,1025],{"id":37,"depth":201,"text":38},{"id":50,"depth":201,"text":51},{"id":57,"depth":201,"text":58},{"id":120,"depth":201,"text":121},{"id":167,"depth":201,"text":168},{"id":175,"depth":201,"text":176},{"id":182,"depth":201,"text":183},"Backend · Admin",{"team":1028,"mine":1029},"Built with two other developers; deployment support from the team.","Nearest-mosque search API and other endpoints, database redesign input, and the entire admin panel.","\u002Fimages\u002Fwork\u002Fdigimosque\u002Fdigi6.png","Nearest-mosque search API and a 15-module admin panel for a digital mosque platform.",[1033,1036],{"label":1034,"url":1035},"Company profile","https:\u002F\u002Fwww.linkedin.com\u002Fcompany\u002Fdigimosque",{"label":1037,"url":1038},"Play Store","https:\u002F\u002Fplay.google.com\u002Fstore\u002Fsearch?q=digimosque&c=apps",{},[1041,1044],{"value":1042,"label":1043},"15","admin modules",{"value":1045,"label":1046},"\u003C 2 mo","to build the admin panel",5,"\u002Fprojects\u002Fdigimosque","Web Developer (Project based)",{"title":935,"description":1031},"projects\u002Fdigimosque",[820,614,1053],"REST API","Mar 2022 — May 2022",2022,"QQH6Fv0FKCc4PabWdjvvxa3eIXSEhma0sX06-imvMJ4",{"id":1058,"title":1059,"architecture":1060,"body":1077,"category":1167,"company":1168,"contribution":1169,"cover":1171,"description":1172,"draft":217,"extension":218,"featured":234,"links":1173,"meta":1174,"metrics":1175,"navigation":234,"order":1181,"path":1182,"role":237,"seo":1183,"stem":1184,"technologies":1185,"timeline":1188,"type":250,"year":1055,"__hash__":1189},"projects_en\u002Fprojects\u002Fjadwalin.md","Jadwalin",[1061,1065,1069,1073],{"id":1062,"label":1063,"detail":1064},"excel","Excel exports from SIAK","Course data and sample schedules, since direct API access wasn't allowed.",{"id":1066,"label":1067,"detail":1068},"import","Import & validation","Familiar Excel workflow for staff.",{"id":1070,"label":1071,"detail":1072},"rules","Rule engine","Department, lecturer, room and credit-hour (SKS) constraints as Laravel rules.",{"id":1074,"label":1075,"detail":1076},"generator","Greedy generator","Automatically proposes a conflict-free schedule.",{"type":32,"value":1078,"toc":1158},[1079,1081,1084,1086,1093,1095,1140,1142,1144,1146,1148,1150,1153,1155],[35,1080,38],{"id":37},[40,1082,1083],{},"The Faculty of Islamic Economics and Business at IAIN Sultan Amai Gorontalo needed to manage course schedules faculty-wide without clashes.",[35,1085,51],{"id":50},[40,1087,1088,1089,1092],{},"Course data lived in the Academic Information System (SIAK), but API access was not permitted. What staff ",[44,1090,1091],{},"did"," have were Excel exports.",[35,1094,58],{"id":57},[60,1096,1097,1103,1133],{},[63,1098,1099,1102],{},[66,1100,1101],{},"Excel-based import",", so staff keep the workflow they know and integration doesn't depend on SIAK access.",[63,1104,1105,1106],{},"Four conflict rules, implemented as Laravel validation rules so new ones are easy to add:\n",[1107,1108,1109,1115,1121,1127],"ol",{},[63,1110,1111,1114],{},[66,1112,1113],{},"Department"," — a major's schedule may not collide.",[63,1116,1117,1120],{},[66,1118,1119],{},"Lecturer"," — a lecturer can't teach two classes at once.",[63,1122,1123,1126],{},[66,1124,1125],{},"Room"," — a room can't be double-booked.",[63,1128,1129,1132],{},[66,1130,1131],{},"Credits (SKS)"," — the course's credits must match the time slot.",[63,1134,1135,1136,1139],{},"An ",[66,1137,1138],{},"automatic schedule generator"," using a greedy algorithm.",[35,1141,121],{"id":120},[123,1143],{":nodes":120},[35,1145,168],{"id":167},[170,1147],{":metrics":172},[35,1149,176],{"id":175},[40,1151,1152],{},"When the ideal integration isn't available, meet users where their data already is. Excel import was less elegant than an API — and far more useful.",[35,1154,183],{"id":182},[185,1156],{":images":1157},"[{\"src\":\"\u002Fimages\u002Fwork\u002Fjadwalin\u002Fjadwalin3.png\",\"alt\":\"Schedule overview\"},{\"src\":\"\u002Fimages\u002Fwork\u002Fjadwalin\u002Fjadwalin1.png\",\"alt\":\"Schedule management\"},{\"src\":\"\u002Fimages\u002Fwork\u002Fjadwalin\u002Fjadwalin2.png\",\"alt\":\"Schedule detail\"}]",{"title":200,"searchDepth":201,"depth":201,"links":1159},[1160,1161,1162,1163,1164,1165,1166],{"id":37,"depth":201,"text":38},{"id":50,"depth":201,"text":51},{"id":57,"depth":201,"text":58},{"id":120,"depth":201,"text":121},{"id":167,"depth":201,"text":168},{"id":175,"depth":201,"text":176},{"id":182,"depth":201,"text":183},"Product · Algorithm","IAIN Sultan Amai Gorontalo",{"mine":1170},"Sole developer — analysis, rules, generator and UI.","\u002Fimages\u002Fwork\u002Fjadwalin\u002Fjadwalin3.png","Faculty-scale course scheduling with conflict rules and a greedy auto-generator, fed by Excel exports instead of a locked API.",[],{},[1176,1178],{"value":388,"label":1177},"conflict rules enforced",{"value":1179,"label":1180},"2 mo","build time",6,"\u002Fprojects\u002Fjadwalin",{"title":1059,"description":1172},"projects\u002Fjadwalin",[820,1186,1187],"Greedy algorithm","Excel import","Apr 2022 — May 2022","9ZWb-vS4PQSxeJBnQW-Hj11V2TCZMOGmWIn5U0whVaY",{"id":1191,"title":1192,"architecture":1193,"body":1194,"category":1226,"company":1227,"contribution":1228,"cover":1231,"description":1232,"draft":217,"extension":218,"featured":217,"links":1233,"meta":1237,"metrics":1238,"navigation":234,"order":1242,"path":1243,"role":1244,"seo":1245,"stem":1246,"technologies":1247,"timeline":1249,"type":250,"year":555,"__hash__":1250},"projects_en\u002Fprojects\u002Fpanah-papua.md","Panah Papua",null,{"type":32,"value":1195,"toc":1220},[1196,1198,1201,1203,1211,1213,1215,1217],[35,1197,38],{"id":37},[40,1199,1200],{},"Panah Papua is an association of Papuan traditional land and forest defenders. They needed a clear, public map of the sago forests of West Papua to support conservation and sustainable land use.",[35,1202,58],{"id":57},[60,1204,1205,1208],{},[63,1206,1207],{},"An interdisciplinary approach with an urban-planner colleague, so the spatial data reflects real geographic features.",[63,1209,1210],{},"A user-friendly map page showing the distribution of sago forest, land cover and administrative coverage, with pop-up details.",[35,1212,168],{"id":167},[170,1214],{":metrics":172},[35,1216,183],{"id":182},[185,1218],{":images":1219},"[{\"src\":\"\u002Fimages\u002Fwork\u002Fpanah-papua\u002Fpp1.jpeg\",\"alt\":\"Topology map\"},{\"src\":\"\u002Fimages\u002Fwork\u002Fpanah-papua\u002Fpp2.jpeg\",\"alt\":\"Administrative coverage map\"},{\"src\":\"\u002Fimages\u002Fwork\u002Fpanah-papua\u002Fpp3.jpeg\",\"alt\":\"Pop-up feature on the map\"}]",{"title":200,"searchDepth":201,"depth":201,"links":1221},[1222,1223,1224,1225],{"id":37,"depth":201,"text":38},{"id":57,"depth":201,"text":58},{"id":167,"depth":201,"text":168},{"id":182,"depth":201,"text":183},"Geo-web","Panah Papua (NGO)",{"team":1229,"mine":1230},"Geography and land-use interpretation came from an urban-planner colleague.","Map page development and spatial data preparation.","\u002Fimages\u002Fwork\u002Fpanah-papua\u002Fpp1.jpeg","A map page and spatial data for the sago forests of West Papua, built for an NGO protecting traditional land.",[1234],{"label":1235,"url":1236},"Live site","https:\u002F\u002Fpanah-papua.vercel.app\u002F",{},[1239],{"value":1240,"label":1241},"2 wk","delivery time",7,"\u002Fprojects\u002Fpanah-papua","Software Engineer & Spatial Data Analyst",{"title":1192,"description":1232},"projects\u002Fpanah-papua",[402,1248,553],"Web maps","Feb 2024 · 2 weeks","B32hRI2GvT0NR6bE6sT84hm4CJPfwcJ-jxAna4uGcKM",{"id":1252,"title":1253,"architecture":1193,"body":1254,"category":1400,"company":1401,"contribution":1193,"cover":1402,"description":1403,"draft":217,"extension":218,"featured":217,"links":1404,"meta":1407,"metrics":1408,"navigation":234,"order":1412,"path":1413,"role":1414,"seo":1415,"stem":1416,"technologies":1417,"timeline":1193,"type":250,"year":822,"__hash__":1419},"projects_en\u002Fprojects\u002Fsindasi.md","Sindasi",{"type":32,"value":1255,"toc":1394},[1256,1258,1261,1263,1280,1384,1386,1389,1391],[35,1257,38],{"id":37},[40,1259,1260],{},"Departments regularly need to pick suitable students — for scholarships, competitions, or research assistance — but criteria change from case to case.",[35,1262,58],{"id":57},[40,1264,1265,1267,1268,1271,1272,1275,1276,1279],{},[66,1266,1253],{}," combines complete student information (academic and non-academic) with a dynamic decision-support engine based on ",[66,1269,1270],{},"AHP"," (Analytical Hierarchy Process) and ",[66,1273,1274],{},"TOPSIS",". Users define criteria and pairwise comparisons, save them as ",[44,1277,1278],{},"preferences",", and generate recommendations from those preferences. Each recommendation can weigh criteria differently.",[653,1281,1282,1301],{},[656,1283,1284],{},[659,1285,1286,1288,1290,1293,1296,1299],{},[662,1287,664],{},[662,1289,1119],{},[662,1291,1292],{},"Head of Dept.",[662,1294,1295],{},"Head of Program",[662,1297,1298],{},"Student",[662,1300,599],{},[676,1302,1303,1322,1339,1354,1369],{},[659,1304,1305,1308,1311,1314,1317,1320],{},[681,1306,1307],{},"Student list & profiles",[681,1309,1310],{},"Advisees",[681,1312,1313],{},"All",[681,1315,1316],{},"Program only",[681,1318,1319],{},"Own",[681,1321,1313],{},[659,1323,1324,1327,1330,1332,1334,1336],{},[681,1325,1326],{},"Criteria master",[681,1328,1329],{},"View",[681,1331,1329],{},[681,1333,1329],{},[681,1335,700],{},[681,1337,1338],{},"Full",[659,1340,1341,1344,1346,1348,1350,1352],{},[681,1342,1343],{},"Preference master",[681,1345,1319],{},[681,1347,1313],{},[681,1349,1319],{},[681,1351,700],{},[681,1353,1313],{},[659,1355,1356,1359,1361,1363,1365,1367],{},[681,1357,1358],{},"Auto recommendation",[681,1360,700],{},[681,1362,686],{},[681,1364,686],{},[681,1366,700],{},[681,1368,700],{},[659,1370,1371,1374,1376,1378,1380,1382],{},[681,1372,1373],{},"Import data",[681,1375,700],{},[681,1377,686],{},[681,1379,700],{},[681,1381,700],{},[681,1383,686],{},[35,1385,176],{"id":175},[40,1387,1388],{},"Making the weights configurable turned a one-off thesis tool into something reusable for many decisions.",[35,1390,183],{"id":182},[185,1392],{":images":1393},"[{\"src\":\"\u002Fimages\u002Fwork\u002Fsindasi\u002Fsindasi1.png\",\"alt\":\"Dashboard\"},{\"src\":\"\u002Fimages\u002Fwork\u002Fsindasi\u002Fsindasi2.png\",\"alt\":\"Recommendation\"},{\"src\":\"\u002Fimages\u002Fwork\u002Fsindasi\u002Fsindasi3.png\",\"alt\":\"Student profile\"}]",{"title":200,"searchDepth":201,"depth":201,"links":1395},[1396,1397,1398,1399],{"id":37,"depth":201,"text":38},{"id":57,"depth":201,"text":58},{"id":175,"depth":201,"text":176},{"id":182,"depth":201,"text":183},"Decision Support","Universitas Negeri Gorontalo","\u002Fimages\u002Fwork\u002Fsindasi\u002Fsindasi1.png","A student information and recommendation system using AHP-TOPSIS with configurable criteria weights.",[1405],{"label":383,"url":1406},"https:\u002F\u002Fejurnal.ung.ac.id\u002Findex.php\u002Fjji\u002Farticle\u002Fview\u002F10246",{},[1409],{"value":1410,"label":1411},"5","user roles",8,"\u002Fprojects\u002Fsindasi","Full-stack Developer & Researcher (Undergraduate thesis)",{"title":1253,"description":1403},"projects\u002Fsindasi",[820,1418,573],"AHP-TOPSIS","yMD-SGuwebZXCrx_25Tlduv_NbXsZaWBVTBHOAEcy3s",{"id":1421,"title":1422,"architecture":1193,"body":1423,"category":1454,"company":1193,"contribution":1193,"cover":1455,"description":1456,"draft":217,"extension":218,"featured":217,"links":1457,"meta":1458,"metrics":1459,"navigation":234,"order":1460,"path":1461,"role":1462,"seo":1463,"stem":1464,"technologies":1465,"timeline":1193,"type":250,"year":1467,"__hash__":1468},"projects_en\u002Fprojects\u002Fkongkong.md","Kongkong",{"type":32,"value":1424,"toc":1449},[1425,1427,1434,1436,1444,1446],[35,1426,38],{"id":37},[40,1428,1429,1430,1433],{},"Students raising money for activities usually pass around a list of donors with little information about the activity itself. The idea: an alternative funding source that explains ",[44,1431,1432],{},"what"," is being funded.",[35,1435,58],{"id":57},[40,1437,1438,1439,1443],{},"I built the interface from scratch with Bootstrap — no template — following mobile-first principles, since students mostly use their phones. See the ",[346,1440,1442],{"href":1441},"\u002Fwork\u002Fkongkong-interface","interface design case"," for the UI details.",[35,1445,183],{"id":182},[185,1447],{":images":1448},"[{\"src\":\"\u002Fimages\u002Fwork\u002Fkongkong\u002Fkongkong1.png\",\"alt\":\"Home\"},{\"src\":\"\u002Fimages\u002Fwork\u002Fkongkong\u002Fkongkong2.png\",\"alt\":\"Campaign\"},{\"src\":\"\u002Fimages\u002Fwork\u002Fkongkong\u002Fkongkong3.png\",\"alt\":\"Campaign detail\"},{\"src\":\"\u002Fimages\u002Fwork\u002Fkongkong\u002Fkongkong4.png\",\"alt\":\"Profile\"}]",{"title":200,"searchDepth":201,"depth":201,"links":1450},[1451,1452,1453],{"id":37,"depth":201,"text":38},{"id":57,"depth":201,"text":58},{"id":182,"depth":201,"text":183},"Full-stack · Practice project","\u002Fimages\u002Fwork\u002Fkongkong\u002Fkongkong1.png","A mobile-first crowdfunding platform for student activities.",[],{},[],9,"\u002Fprojects\u002Fkongkong","Front-end Developer",{"title":1422,"description":1456},"projects\u002Fkongkong",[820,1466,244],"Bootstrap",2020,"T0IPD6mpTvNz-i5Uz5mX_W_uo0d9WIDEUo7BdSCSJn4",{"id":1470,"title":1471,"architecture":1193,"body":1472,"category":1539,"company":1540,"contribution":1193,"cover":1541,"description":1542,"draft":217,"extension":218,"featured":217,"links":1543,"meta":1547,"metrics":1548,"navigation":234,"order":1553,"path":1554,"role":1555,"seo":1556,"stem":1557,"technologies":1558,"timeline":1562,"type":250,"year":408,"__hash__":1563},"projects_en\u002Fprojects\u002Fipb-summer-2023.md","Melon Leaf Clustering",{"type":32,"value":1473,"toc":1533},[1474,1476,1479,1481,1513,1515,1517,1528,1530],[35,1475,38],{"id":37},[40,1477,1478],{},"At the International Summer Course on AI and Optimization for Smart Agriculture (IPB, Oct 2023), our team explored whether melon leaf images could be grouped automatically to support disease diagnosis and crop management.",[35,1480,58],{"id":57},[60,1482,1483,1489,1496,1506],{},[63,1484,1485,1486,352],{},"Extracted texture features with the ",[66,1487,1488],{},"gray-level co-occurrence matrix (GLCM)",[63,1490,1491,1492,1495],{},"Clustered images with ",[66,1493,1494],{},"K-Means"," (scikit-learn, OpenCV for pre-processing).",[63,1497,1498,1499,596,1502,1505],{},"Chose the number of clusters with ",[66,1500,1501],{},"SSE",[66,1503,1504],{},"silhouette score"," — useful values ranged 3–6; we used 6 because it gave the most information to plant experts.",[63,1507,1508,1509,1512],{},"Reviewed clusters ",[66,1510,1511],{},"with plant experts",": they mapped to diseased leaves, nutrient deficiencies, healthy plants, and similar-symptom groups.",[35,1514,168],{"id":167},[170,1516],{":metrics":172},[40,1518,1519,1520,1523,1524,1527],{},"Our team won ",[66,1521,1522],{},"Best Team",", and I received the ",[66,1525,1526],{},"Best Local Participant"," award.",[35,1529,183],{"id":182},[185,1531],{":images":1532},"[{\"src\":\"\u002Fimages\u002Fwork\u002Fipb-summer-2023\u002F2.jpeg\",\"alt\":\"Clusters\"},{\"src\":\"\u002Fimages\u002Fwork\u002Fipb-summer-2023\u002F1.jpeg\",\"alt\":\"Cluster plot\"},{\"src\":\"\u002Fimages\u002Fwork\u002Fipb-summer-2023\u002F3.jpeg\",\"alt\":\"SSE score\"},{\"src\":\"\u002Fimages\u002Fwork\u002Fipb-summer-2023\u002F4.jpeg\",\"alt\":\"Silhouette score\"},{\"src\":\"\u002Fimages\u002Fwork\u002Fipb-summer-2023\u002F5.jpeg\",\"alt\":\"Team presentation\"},{\"src\":\"\u002Fimages\u002Fwork\u002Fipb-summer-2023\u002F6.jpg\",\"alt\":\"Award\"}]",{"title":200,"searchDepth":201,"depth":201,"links":1534},[1535,1536,1537,1538],{"id":37,"depth":201,"text":38},{"id":57,"depth":201,"text":58},{"id":167,"depth":201,"text":168},{"id":182,"depth":201,"text":183},"AI · Machine Learning","IPB International Summer Course","\u002Fimages\u002Fwork\u002Fipb-summer-2023\u002F1.jpeg","Unsupervised clustering of melon leaf images with K-Means and GLCM texture features — Best Team at the IPB International Summer Course.",[1544],{"label":1545,"url":1546},"About the course","https:\u002F\u002Fcsagri23.apps.cs.ipb.ac.id\u002F",{},[1549,1551],{"value":229,"label":1550},"clusters validated with plant experts",{"value":1522,"label":1552},"award",10,"\u002Fprojects\u002Fipb-summer-2023","Machine Learning Engineer",{"title":1471,"description":1542},"projects\u002Fipb-summer-2023",[402,1559,1560,1494,1561],"scikit-learn","OpenCV","GLCM","8–20 Oct 2023","my2NANinSpb5yDEEB8gkkbOk8qQLUzuUlHFGXBtBWsg",{"id":4,"title":5,"architecture":1565,"body":1572,"category":211,"company":212,"contribution":1678,"cover":215,"description":216,"draft":217,"extension":218,"featured":217,"links":1679,"meta":1681,"metrics":1682,"navigation":234,"order":235,"path":236,"role":237,"seo":1686,"stem":239,"technologies":1687,"timeline":249,"type":250,"year":251,"__hash__":252},[1566,1567,1568,1569,1570,1571],{"id":8,"label":9,"detail":10},{"id":12,"label":13,"detail":14},{"id":16,"label":17,"detail":18},{"id":20,"label":21,"detail":22},{"id":24,"label":25,"detail":26},{"id":28,"label":29,"detail":30},{"type":32,"value":1573,"toc":1668},[1574,1576,1580,1582,1584,1586,1620,1622,1624,1626,1650,1652,1654,1656,1658,1660,1662,1666],[35,1575,38],{"id":37},[40,1577,42,1578,47],{},[44,1579,46],{},[35,1581,51],{"id":50},[40,1583,54],{},[35,1585,58],{"id":57},[60,1587,1588,1600,1604,1608,1616],{},[63,1589,1590,69,1592,73,1594,78,1596,78,1598,85],{},[66,1591,68],{},[66,1593,72],{},[75,1595,77],{},[75,1597,81],{},[75,1599,84],{},[63,1601,1602,91],{},[66,1603,90],{},[63,1605,1606,97],{},[66,1607,96],{},[63,1609,1610,103,1612,107,1614,111],{},[66,1611,102],{},[44,1613,106],{},[44,1615,110],{},[63,1617,1618,117],{},[66,1619,116],{},[35,1621,121],{"id":120},[123,1623],{":nodes":120},[35,1625,128],{"id":127},[60,1627,1628,1632,1636,1640,1644],{},[63,1629,1630,136],{},[66,1631,135],{},[63,1633,1634,142],{},[66,1635,141],{},[63,1637,1638,148],{},[66,1639,147],{},[63,1641,1642,154],{},[66,1643,153],{},[63,1645,1646,160,1648,164],{},[66,1647,159],{},[75,1649,163],{},[35,1651,168],{"id":167},[170,1653],{":metrics":172},[35,1655,176],{"id":175},[40,1657,179],{},[35,1659,183],{"id":182},[185,1661],{":images":187},[40,1663,1664],{},[191,1665],{"alt":193,"src":194},[185,1667],{":images":197,"fit":198},{"title":200,"searchDepth":201,"depth":201,"links":1669},[1670,1671,1672,1673,1674,1675,1676,1677],{"id":37,"depth":201,"text":38},{"id":50,"depth":201,"text":51},{"id":57,"depth":201,"text":58},{"id":120,"depth":201,"text":121},{"id":127,"depth":201,"text":128},{"id":167,"depth":201,"text":168},{"id":175,"depth":201,"text":176},{"id":182,"depth":201,"text":183},{"mine":214},[1680],{"label":221,"url":222},{},[1683,1684,1685],{"value":226,"label":227},{"value":229,"label":230},{"value":232,"label":233},{"title":5,"description":216},[241,242,243,244,245,246,247,248],{"id":1689,"title":1690,"architecture":1193,"body":1691,"category":1822,"company":1823,"contribution":1193,"cover":1736,"description":1824,"draft":217,"extension":218,"featured":217,"links":1825,"meta":1826,"metrics":1827,"navigation":234,"order":1828,"path":1829,"role":1830,"seo":1831,"stem":1832,"technologies":1833,"timeline":1193,"type":1839,"year":822,"__hash__":1840},"projects_en\u002Fprojects\u002Fgenbi-branding.md","GenBI Gorontalo Branding",{"type":32,"value":1692,"toc":1813},[1693,1697,1700,1704,1707,1711,1715,1718,1724,1731,1737,1741,1744,1749,1755,1759,1762,1766,1770,1776,1782,1785,1791,1797,1803,1806,1810],[35,1694,1696],{"id":1695},"brief","Brief",[40,1698,1699],{},"Present GenBI as a community with a clear vision and a directed target, with a design that is easy to remember — a first step toward the 2025 target, starting from internal management and GenBI Gorontalo's social-media presence.",[35,1701,1703],{"id":1702},"the-challenge","The challenge",[40,1705,1706],{},"GenBI Gorontalo brings together Bank Indonesia scholarship recipients from three campus commissariats, organised into seven departments. With that many people posting, the risk was every post looking like it came from a different organisation. As chairman I could set the direction; as the designer I had to make it something people would actually reuse.",[1708,1709],"process-steps",{":steps":1710},"[{\"title\":\"Words first\",\"text\":\"Agree on the 2025 vision and its values before drawing anything — the identity had to say something specific.\"},{\"title\":\"One mark for the vision\",\"text\":\"Turn the vision into a single emblem that could sit on every post as a quiet reminder.\"},{\"title\":\"One family of symbols\",\"text\":\"Give each department its own symbol, all built from the same circle, stroke and navy.\"},{\"title\":\"Templates that carry it\",\"text\":\"Put the system into feed templates and the organigram, so members use it without thinking about it.\"}]",[35,1712,1714],{"id":1713},"the-vision-as-a-mark","The vision, as a mark",[40,1716,1717],{},"The 2025 vision and values were formulated as:",[1719,1720,1721],"blockquote",{},[40,1722,1723],{},"Becoming the best new generation of Indonesia in Sulawesi, holding the values of kinship, mutual protection, determination, professionalism, and activeness (KESATRIA).",[40,1725,1726,1727,1730],{},"That vision became a logo — ",[66,1728,1729],{},"Patuju Kesatria 2025"," — repeated across GenBI Gorontalo posts as a reminder. An upright, pointed form is lifted by a pair of wings resting on curling waves: one silhouette that still reads at the size of a footer icon.",[40,1732,1733],{},[191,1734],{"alt":1735,"src":1736},"Community vision logo","\u002Fimages\u002Fwork\u002Fgenbi-branding\u002Flogo-visi-kesatria-2025.png",[35,1738,1740],{"id":1739},"seven-symbols-one-family","Seven symbols, one family",[40,1742,1743],{},"Each department received its own symbol. They share one construction — a circle (often broken open), a single stroke weight with rounded ends, and one navy — so any one of them is recognisably GenBI, and together they read as a set.",[1745,1746],"symbol-explorer",{":items":1747,"caption":1748},"[{\"src\":\"\u002Fimages\u002Fwork\u002Fgenbi-branding\u002Fsymbols\u002Fpengurus-inti.png\",\"label\":\"Core Management\",\"meaning\":\"A ship's helm: the core team steers, and every spoke meets at one centre.\"},{\"src\":\"\u002Fimages\u002Fwork\u002Fgenbi-branding\u002Fsymbols\u002Fkewirausahaan.png\",\"label\":\"Entrepreneurship\",\"meaning\":\"Dots and lines shaped like people helping each other.\"},{\"src\":\"\u002Fimages\u002Fwork\u002Fgenbi-branding\u002Fsymbols\u002Fagama-pendidikan.png\",\"label\":\"Religion & Education\",\"meaning\":\"A growing swirl that represents guidance and knowledge.\"},{\"src\":\"\u002Fimages\u002Fwork\u002Fgenbi-branding\u002Fsymbols\u002Fkesehatan-masyarakat.png\",\"label\":\"Public Health\",\"meaning\":\"A dot held inside a circle: care and protection.\"},{\"src\":\"\u002Fimages\u002Fwork\u002Fgenbi-branding\u002Fsymbols\u002Flingkungan-hidup.png\",\"label\":\"Environment\",\"meaning\":\"A small leaf with root-like lines: cleanliness and freshness.\"},{\"src\":\"\u002Fimages\u002Fwork\u002Fgenbi-branding\u002Fsymbols\u002Forganisasi-keanggotaan.png\",\"label\":\"Organization & Membership\",\"meaning\":\"A dot with one line piercing the circle — embracing members and removing partitions.\"},{\"src\":\"\u002Fimages\u002Fwork\u002Fgenbi-branding\u002Fsymbols\u002Fkerjasama-kemitraan.png\",\"label\":\"Cooperation & Partnership\",\"meaning\":\"Fast-flowing water: the spirit to explore, the spearhead of external relations.\"}]","Cropped from the original symbol sheet. Select a symbol to read what it stands for.",[40,1750,1751],{},[191,1752],{"alt":1753,"src":1754},"Division symbols","\u002Fimages\u002Fwork\u002Fgenbi-branding\u002Fsimbol-bidang-departemen.png",[35,1756,1758],{"id":1757},"palette","Palette",[40,1760,1761],{},"A deep navy carries the symbols and headings. Red, green and yellow appear only as a thin stripe at the bottom of each template — enough color to feel lively, never enough to compete with the content.",[1763,1764],"color-palette",{":colors":1765},"[{\"hex\":\"#184E78\",\"name\":\"Symbol navy\",\"role\":\"Symbols, headings, the vision mark\"},{\"hex\":\"#0F2751\",\"name\":\"Deep navy\",\"role\":\"First band of the footer stripe\"},{\"hex\":\"#E94335\",\"name\":\"Red\",\"role\":\"Footer stripe accent\"},{\"hex\":\"#20834F\",\"name\":\"Green\",\"role\":\"Footer stripe accent\"},{\"hex\":\"#FABC05\",\"name\":\"Yellow\",\"role\":\"Footer stripe accent\"}]",[35,1767,1769],{"id":1768},"the-system-in-use","The system in use",[40,1771,1772,1775],{},[66,1773,1774],{},"Feed template."," Every post shares the same frame: partner logos in the header (Bank Indonesia, GenBI Gorontalo and the three campuses), a light grid for the content, and a footer with the vision mark, social handles and the color stripe. Whoever makes the post only fills the middle.",[40,1777,1778],{},[191,1779],{"alt":1780,"src":1781},"Instagram feed template","\u002Fimages\u002Fwork\u002Fgenbi-branding\u002Ftemplate-feed-instagram.png",[40,1783,1784],{},"The two fixed bands, up close:",[40,1786,1787],{},[191,1788],{"alt":1789,"src":1790},"Template header with the partner logos","\u002Fimages\u002Fwork\u002Fgenbi-branding\u002Ftemplate-header.png",[40,1792,1793],{},[191,1794],{"alt":1795,"src":1796},"Template footer with the vision mark, social handles and the four-color stripe","\u002Fimages\u002Fwork\u002Fgenbi-branding\u002Ftemplate-footer.png",[40,1798,1799,1802],{},[66,1800,1801],{},"Organigram."," The department symbols return as large, faint watermarks behind each department head — the structure chart doubles as a key to the symbols.",[185,1804],{":images":1805},"[{\"src\":\"\u002Fimages\u002Fwork\u002Fgenbi-branding\u002Fdesain-struktur-organisasi.png\",\"alt\":\"Organization structure design\",\"caption\":\"Organigram for the 2021–2022 board.\"},{\"src\":\"\u002Fimages\u002Fwork\u002Fgenbi-branding\u002Forganigram-detail.png\",\"alt\":\"Detail of the organigram with a symbol used as a watermark\",\"caption\":\"Detail: the Core Management helm sits behind the chairman's photo.\"}]",[35,1807,1809],{"id":1808},"looking-back","Looking back",[40,1811,1812],{},"The strongest decision was keeping every symbol on the same construction — it is why seven different ideas still look like one organisation. If I did it again, I would write the rules down as a one-page guideline (clear space, minimum sizes, when to use the stripe) so the next board could keep the system going without me.",{"title":200,"searchDepth":201,"depth":201,"links":1814},[1815,1816,1817,1818,1819,1820,1821],{"id":1695,"depth":201,"text":1696},{"id":1702,"depth":201,"text":1703},{"id":1713,"depth":201,"text":1714},{"id":1739,"depth":201,"text":1740},{"id":1757,"depth":201,"text":1758},{"id":1768,"depth":201,"text":1769},{"id":1808,"depth":201,"text":1809},"Brand identity","GenBI Gorontalo","A vision mark, seven division symbols and a set of templates that gave a scholarship community one clear, memorable identity.",[],{},[],20,"\u002Fprojects\u002Fgenbi-branding","Designer & Chairman",{"title":1690,"description":1824},"projects\u002Fgenbi-branding",[1834,1835,1836,1837,1838],"Branding","Logo","Iconography","Social media","Visual system","design","i1_vHgp9mIGDG0_QsOTamOvzlp3PS-Q7ubcbGFzEYAA",{"id":1842,"title":1843,"architecture":1193,"body":1844,"category":1835,"company":1914,"contribution":1193,"cover":1865,"description":1915,"draft":217,"extension":218,"featured":217,"links":1916,"meta":1917,"metrics":1918,"navigation":234,"order":1919,"path":1920,"role":1921,"seo":1922,"stem":1923,"technologies":1924,"timeline":1193,"type":1839,"year":1926,"__hash__":1927},"projects_en\u002Fprojects\u002Fhexstudio-logo.md","HEXSTUDIO Logo",{"type":32,"value":1845,"toc":1907},[1846,1848,1851,1853,1860,1866,1870,1877,1883,1886,1890,1893,1897,1904],[35,1847,1696],{"id":1695},[40,1849,1850],{},"A studio logo that is modern yet friendly, and signals design expertise.",[35,1852,58],{"id":57},[40,1854,1855,1856,1859],{},"Negative space forms the word ",[66,1857,1858],{},"HEX",". The palette comes from the three primaries of digital design — red, green and blue — signalling an understanding of design fundamentals. The tones are calm rather than bright, to keep the impression friendly.",[40,1861,1862],{},[191,1863],{"alt":1864,"src":1865},"HEXSTUDIO logo","\u002Fimages\u002Fwork\u002Fhexstudio-logo\u002Flogo-hexstudio.png",[35,1867,1869],{"id":1868},"how-the-letters-appear","How the letters appear",[40,1871,1872,1873,1876],{},"Nothing in the mark is drawn as a letter. Each one is made of simple blocks, and the letter only exists in the white space they leave behind — the kind of detail a design client notices, and a quiet proof that the studio thinks about what ",[44,1874,1875],{},"isn't"," there.",[40,1878,1879],{},[191,1880],{"alt":1881,"src":1882},"How the HEXSTUDIO mark spells H, E and X with negative space","\u002Fimages\u002Fwork\u002Fhexstudio-logo\u002Fhexstudio-negative-space.svg",[1708,1884],{":steps":1885},"[{\"title\":\"Start from the name\",\"text\":\"\\\"HEX\\\" is short and geometric — a good candidate for letters built from blocks rather than drawn.\"},{\"title\":\"Blocks, not strokes\",\"text\":\"Rectangles and triangles only: crisp at any size and easy to reproduce in any medium.\"},{\"title\":\"Carve the letters out\",\"text\":\"Cut gaps, slots and channels until H, E and X appear in the negative space.\"},{\"title\":\"One primary per letter\",\"text\":\"Red, green and blue — the RGB of every screen — each softened so the mark feels approachable.\"}]",[35,1887,1889],{"id":1888},"color","Color",[1763,1891],{":colors":1892},"[{\"hex\":\"#E74C3C\",\"name\":\"Soft red\",\"role\":\"H\"},{\"hex\":\"#2FAB63\",\"name\":\"Soft green\",\"role\":\"E\"},{\"hex\":\"#6CB8BE\",\"name\":\"Soft blue\",\"role\":\"X\"},{\"hex\":\"#393939\",\"name\":\"Charcoal\",\"role\":\"Dark backgrounds\"}]",[35,1894,1896],{"id":1895},"variants","Variants",[40,1898,1899,1900,1903],{},"The wordmark is set in widely tracked capitals with ",[66,1901,1902],{},"DIGITAL ART STUDIO"," as a smaller descriptor underneath. Because the letters live in the negative space, the mark survives being reduced to a single color — it still reads as HEX in light gray on charcoal.",[185,1905],{":images":1906,"fit":198},"[{\"src\":\"\u002Fimages\u002Fwork\u002Fhexstudio-logo\u002Fhexstudio-primary.png\",\"alt\":\"Primary logo on white\",\"caption\":\"Primary — full color on white.\"},{\"src\":\"\u002Fimages\u002Fwork\u002Fhexstudio-logo\u002Fhexstudio-color-dark.png\",\"alt\":\"Full-color logo on charcoal\",\"caption\":\"Full color on charcoal.\"},{\"src\":\"\u002Fimages\u002Fwork\u002Fhexstudio-logo\u002Fhexstudio-mono-dark.png\",\"alt\":\"Single-color logo on charcoal\",\"caption\":\"Single color — the negative space still spells HEX.\"}]",{"title":200,"searchDepth":201,"depth":201,"links":1908},[1909,1910,1911,1912,1913],{"id":1695,"depth":201,"text":1696},{"id":57,"depth":201,"text":58},{"id":1868,"depth":201,"text":1869},{"id":1888,"depth":201,"text":1889},{"id":1895,"depth":201,"text":1896},"HEXSTUDIO","Negative space that spells HEX, colored with calm RGB primaries.",[],{},[],21,"\u002Fprojects\u002Fhexstudio-logo","Designer",{"title":1843,"description":1915},"projects\u002Fhexstudio-logo",[1835,1834,1925],"Negative space",2019,"cQdhUs8sr4Jqr7A0o9nK-qXA_jCbH0JbPwmT6XxSOAY",{"id":1929,"title":1930,"architecture":1193,"body":1931,"category":1835,"company":2009,"contribution":1193,"cover":1952,"description":2010,"draft":217,"extension":218,"featured":217,"links":2011,"meta":2012,"metrics":2013,"navigation":234,"order":2014,"path":2015,"role":1921,"seo":2016,"stem":2017,"technologies":2018,"timeline":1193,"type":1839,"year":1926,"__hash__":2021},"projects_en\u002Fprojects\u002Fkatili-corp-logo.md","Katili Corp Logo",{"type":32,"value":1932,"toc":2002},[1933,1935,1938,1940,1947,1953,1957,1960,1963,1967,1970,1976,1979,1982,1986,1989,1996],[35,1934,1696],{"id":1695},[40,1936,1937],{},"A modern, minimalist logo that also tells the history of a company founded through a student's hard work.",[35,1939,58],{"id":57},[40,1941,1942,1943,1946],{},"The mark is built on the ",[66,1944,1945],{},"golden ratio"," (1.618), so every angle and plane stays balanced — that is the \"modern and minimalist\". Its shape is a bag being dragged; behind it, a tail of wind forms a Fibonacci curve. The bag is the student; the curve is every struggle, turned into a beautiful stroke.",[40,1948,1949],{},[191,1950],{"alt":1951,"src":1952},"Katili Corp logo explanation","\u002Fimages\u002Fwork\u002Fkatili-corp-logo\u002Flogo-katili-corp.png",[35,1954,1956],{"id":1955},"the-story-in-two-shapes","The story in two shapes",[40,1958,1959],{},"The whole mark is one idea split into two parts: what the student carries, and the road behind them.",[185,1961],{":images":1962,"fit":198},"[{\"src\":\"\u002Fimages\u002Fwork\u002Fkatili-corp-logo\u002Fkatili-formula.png\",\"alt\":\"The spiral and the bag combined into one mark\",\"caption\":\"Spiral + bag = the mark: the road behind, and what the student carries.\"}]",[35,1964,1966],{"id":1965},"construction","Construction",[40,1968,1969],{},"\"Minimalist\" is easy to say and hard to defend. Here it is defended by one rule: every curve and proportion comes from the Fibonacci sequence, the whole-number approximation of 1 : 1.618.",[40,1971,1972],{},[191,1973],{"alt":1974,"src":1975},"The Fibonacci squares and golden spiral behind the Katili Corp mark","\u002Fimages\u002Fwork\u002Fkatili-corp-logo\u002Fkatili-fibonacci.svg",[1708,1977],{":steps":1978},"[{\"title\":\"Golden rectangle\",\"text\":\"Squares of 1, 1, 2, 3, 5 and 8 tile a rectangle; a quarter-circle in each one draws the spiral — the wind behind the bag.\"},{\"title\":\"Circles for the bag\",\"text\":\"Overlapping circles of related sizes define the bag's body, its opening and the knot on top.\"},{\"title\":\"One stroke weight\",\"text\":\"Everything is drawn as a single monoline in teal, so the mark stays light and works as an outline at small sizes.\"}]",[185,1980],{":images":1981,"fit":198},"[{\"src\":\"\u002Fimages\u002Fwork\u002Fkatili-corp-logo\u002Fkatili-golden-grid.png\",\"alt\":\"Golden-ratio grid used to draw the spiral\",\"caption\":\"The golden grid — the spiral's curves are cut from these circles.\"},{\"src\":\"\u002Fimages\u002Fwork\u002Fkatili-corp-logo\u002Fkatili-circle-construction.png\",\"alt\":\"Circle construction of the bag\",\"caption\":\"The bag, constructed from overlapping circles.\"}]",[35,1983,1985],{"id":1984},"color-type","Color & type",[1763,1987],{":colors":1988},"[{\"hex\":\"#2C9C92\",\"name\":\"Teal\",\"role\":\"The mark and wordmark\"},{\"hex\":\"#27292A\",\"name\":\"Charcoal\",\"role\":\"Construction sheets and dark backgrounds\"}]",[40,1990,1991,1992,1995],{},"The wordmark ",[66,1993,1994],{},"KATILI CORP"," is set in thin geometric capitals that match the weight of the monoline mark, so logo and name read as one piece.",[40,1997,1998],{},[191,1999],{"alt":2000,"src":2001},"Primary Katili Corp logo","\u002Fimages\u002Fwork\u002Fkatili-corp-logo\u002Fkatili-primary.png",{"title":200,"searchDepth":201,"depth":201,"links":2003},[2004,2005,2006,2007,2008],{"id":1695,"depth":201,"text":1696},{"id":57,"depth":201,"text":58},{"id":1955,"depth":201,"text":1956},{"id":1965,"depth":201,"text":1966},{"id":1984,"depth":201,"text":1985},"Katili Corp","A golden-ratio mark that tells the story of a company built by a student's hard work.",[],{},[],22,"\u002Fprojects\u002Fkatili-corp-logo",{"title":1930,"description":2010},"projects\u002Fkatili-corp-logo",[1835,2019,2020],"Golden ratio","Monoline","TrqnlmTezhnlX9YHzvkFJTTPyHxCbdJIllGY3uUldj4",{"id":2023,"title":2024,"architecture":1193,"body":2025,"category":1835,"company":2082,"contribution":1193,"cover":2046,"description":2083,"draft":217,"extension":218,"featured":217,"links":2084,"meta":2085,"metrics":2086,"navigation":234,"order":2087,"path":2088,"role":1921,"seo":2089,"stem":2090,"technologies":2091,"timeline":1193,"type":1839,"year":1926,"__hash__":2093},"projects_en\u002Fprojects\u002Fkotaluwuk-logo.md","Kotaluwuk.com Logo",{"type":32,"value":2026,"toc":2076},[2027,2029,2032,2034,2041,2047,2051,2054,2060,2063,2067,2070,2073],[35,2028,1696],{"id":1695},[40,2030,2031],{},"A modern, minimalist logo for a tourism website, using Luwuk's icon — the maleo bird.",[35,2033,58],{"id":57},[40,2035,2036,2037,2040],{},"A maleo bird in front of a sun and clouds. The clouds sit ",[44,2038,2039],{},"below"," the bird, so it appears to fly high — Luwuk is not only beautiful, but also wise and advanced.",[40,2042,2043],{},[191,2044],{"alt":2045,"src":2046},"Kotaluwuk.com logo","\u002Fimages\u002Fwork\u002Fkotaluwuk-logo\u002Flogo-kotaluwuk.png",[35,2048,2050],{"id":2049},"reading-the-mark","Reading the mark",[40,2052,2053],{},"The emblem is meant to be read top to bottom, like a postcard: sky, subject, horizon. Every element is either a solid white shape or a thin white line, so the whole scene holds together in one color.",[40,2055,2056],{},[191,2057],{"alt":2058,"src":2059},"Reading the Kotaluwuk.com mark from top to bottom","\u002Fimages\u002Fwork\u002Fkotaluwuk-logo\u002Fkotaluwuk-layers.svg",[1708,2061],{":steps":2062},"[{\"title\":\"A local icon\",\"text\":\"The maleo is the bird people already associate with the region, so the logo needs no explanation to locals.\"},{\"title\":\"Placement tells the story\",\"text\":\"Putting the clouds lower than the bird is the whole message: it is flying high.\"},{\"title\":\"A contained shape\",\"text\":\"The scene sits inside a rounded square, so it works as a social-media avatar or site icon without redrawing.\"}]",[35,2064,2066],{"id":2065},"color-variants","Color & variants",[1763,2068],{":colors":2069},"[{\"hex\":\"#5E9DD3\",\"name\":\"Sky blue\",\"role\":\"Emblem background and wordmark\"},{\"hex\":\"#FFFFFF\",\"name\":\"White\",\"role\":\"Bird, sun, clouds and lines\"},{\"hex\":\"#000000\",\"name\":\"Black\",\"role\":\"Single-color versions\"}]",[40,2071,2072],{},"Because the drawing is built from white shapes and thin lines, it converts cleanly to a single color — an outlined version for light backgrounds and an inverted one for dark.",[185,2074],{":images":2075,"fit":198},"[{\"src\":\"\u002Fimages\u002Fwork\u002Fkotaluwuk-logo\u002Fkotaluwuk-primary.png\",\"alt\":\"Primary logo in sky blue\",\"caption\":\"Primary — sky blue emblem with the wordmark.\"},{\"src\":\"\u002Fimages\u002Fwork\u002Fkotaluwuk-logo\u002Fkotaluwuk-mono-light.png\",\"alt\":\"Black single-color logo on light gray\",\"caption\":\"Single color on light backgrounds.\"},{\"src\":\"\u002Fimages\u002Fwork\u002Fkotaluwuk-logo\u002Fkotaluwuk-mono-dark.png\",\"alt\":\"White single-color logo on black\",\"caption\":\"Inverted for dark backgrounds.\"}]",{"title":200,"searchDepth":201,"depth":201,"links":2077},[2078,2079,2080,2081],{"id":1695,"depth":201,"text":1696},{"id":57,"depth":201,"text":58},{"id":2049,"depth":201,"text":2050},{"id":2065,"depth":201,"text":2066},"Kotaluwuk.com","A maleo bird flying above the clouds for a tourism website from Luwuk.",[],{},[],23,"\u002Fprojects\u002Fkotaluwuk-logo",{"title":2024,"description":2083},"projects\u002Fkotaluwuk-logo",[1835,1834,2092],"Tourism","17TiSies6mLkSXFtLlu52NeqVSebaYTOLVPluqd5t5Q",{"id":2095,"title":2096,"architecture":1193,"body":2097,"category":2194,"company":1193,"contribution":1193,"cover":2195,"description":2196,"draft":217,"extension":218,"featured":217,"links":2197,"meta":2198,"metrics":2199,"navigation":234,"order":2200,"path":2201,"role":2202,"seo":2203,"stem":2204,"technologies":2205,"timeline":1193,"type":1839,"year":1467,"__hash__":2209},"projects_en\u002Fprojects\u002Fkongkong-interface.md","Kongkong Interface",{"type":32,"value":2098,"toc":2186},[2099,2101,2104,2106,2113,2116,2120,2131,2137,2141,2144,2148,2151,2157,2160,2163,2169,2172,2178,2180,2183],[35,2100,1696],{"id":1695},[40,2102,2103],{},"An interface for students: flexible, responsive, and able to show activities run by students and student organizations.",[35,2105,58],{"id":57},[40,2107,2108,2109,352],{},"Built from scratch with Bootstrap — no template — prioritising the mobile layout, since phones are what students use most. The engineering side is in the ",[346,2110,2112],{"href":2111},"\u002Fwork\u002Fkongkong","Kongkong project",[185,2114],{":images":2115},"[{\"src\":\"\u002Fimages\u002Fwork\u002Fkongkong-interface\u002Findex-desktop.png\",\"alt\":\"Index page, desktop\"},{\"src\":\"\u002Fimages\u002Fwork\u002Fkongkong-interface\u002Findex-mobile.png\",\"alt\":\"Index page, mobile\"},{\"src\":\"\u002Fimages\u002Fwork\u002Fkongkong-interface\u002Fprofil-desktop.png\",\"alt\":\"Profile page, desktop\"},{\"src\":\"\u002Fimages\u002Fwork\u002Fkongkong-interface\u002Fprofil-mobile.png\",\"alt\":\"Profile page, mobile\"}]",[35,2117,2119],{"id":2118},"two-people-two-journeys","Two people, two journeys",[40,2121,2122,2123,2126,2127,2130],{},"Kongkong serves two very different visitors. A ",[66,2124,2125],{},"supporter"," arrives from a shared link and should reach a project and back it without creating an account. A ",[66,2128,2129],{},"student or student organisation"," signs in to publish proposals and follow their progress. Every screen was designed around one of those two journeys, with one primary action each.",[40,2132,2133],{},[191,2134],{"alt":2135,"src":2136},"The two journeys the Kongkong interface was designed around","\u002Fimages\u002Fwork\u002Fkongkong-interface\u002Fkongkong-user-flow.svg",[35,2138,2140],{"id":2139},"design-decisions","Design decisions",[1708,2142],{":steps":2143},"[{\"title\":\"Mobile first\",\"text\":\"Layouts were designed at phone width first, then allowed to spread into columns on desktop — not squeezed down afterwards.\"},{\"title\":\"One search field\",\"text\":\"The home page has a single headline, a friendly greeting (#SohibKongkong) and one search box. Nothing competes with it.\"},{\"title\":\"Progress on every card\",\"text\":\"Each project card shows its owner, date and a funding bar, so supporters can compare projects at a glance.\"},{\"title\":\"Navigation within thumb reach\",\"text\":\"On mobile the top navigation moves to a bottom tab bar: three tabs for guests, five once signed in.\"},{\"title\":\"The main action in the centre\",\"text\":\"For signed-in students the centre tab is “+” — creating a proposal sits exactly where the thumb rests.\"},{\"title\":\"Same parts, every size\",\"text\":\"Cards, tabs and the activity summary are the same components on desktop and mobile, only rearranged.\"}]",[35,2145,2147],{"id":2146},"component-breakdown","Component breakdown",[40,2149,2150],{},"Pulled out of the screens above, these are the pieces the whole interface is built from.",[40,2152,2153],{},[191,2154],{"alt":2155,"src":2156},"Home page hero with headline, greeting and a single search field","\u002Fimages\u002Fwork\u002Fkongkong-interface\u002Fdetail-hero.png",[185,2158],{":images":2159,"fit":198},"[{\"src\":\"\u002Fimages\u002Fwork\u002Fkongkong-interface\u002Fdetail-project-card.png\",\"alt\":\"Project card with owner avatar and progress\",\"caption\":\"Project card — cover image, title, owner avatar, date and funding percentage.\"},{\"src\":\"\u002Fimages\u002Fwork\u002Fkongkong-interface\u002Fdetail-activity.png\",\"alt\":\"Activity summary with proposal, event and wait counts\",\"caption\":\"Activity summary — proposals, events and items waiting, as three numbers.\"},{\"src\":\"\u002Fimages\u002Fwork\u002Fkongkong-interface\u002Fdetail-profile-links.png\",\"alt\":\"Profile links list\",\"caption\":\"Profile links — website, social accounts and email in one scannable list.\"}]",[40,2161,2162],{},"On mobile the navigation is a bottom tab bar. Guests get three tabs — proposals, documentation and log in, the same items as the desktop navigation:",[40,2164,2165],{},[191,2166],{"alt":2167,"src":2168},"Bottom tab bar for guests","\u002Fimages\u002Fwork\u002Fkongkong-interface\u002Fdetail-tabbar-guest.png",[40,2170,2171],{},"Once signed in it grows to five, and the \"+\" for a new proposal takes the centre:",[40,2173,2174],{},[191,2175],{"alt":2176,"src":2177},"Bottom tab bar for signed-in students","\u002Fimages\u002Fwork\u002Fkongkong-interface\u002Fdetail-tabbar-user.png",[35,2179,1758],{"id":1757},[40,2181,2182],{},"Built on Bootstrap's defaults on purpose: a familiar blue for actions, a lighter teal for links and names, and a cool gray surface — quick to build, and easy for the next developer to extend.",[1763,2184],{":colors":2185},"[{\"hex\":\"#007BFF\",\"name\":\"Action blue\",\"role\":\"Progress bars and primary buttons\"},{\"hex\":\"#17A2B8\",\"name\":\"Link teal\",\"role\":\"Project titles and names\"},{\"hex\":\"#F4F6F8\",\"name\":\"Surface gray\",\"role\":\"Page and hero background\"}]",{"title":200,"searchDepth":201,"depth":201,"links":2187},[2188,2189,2190,2191,2192,2193],{"id":1695,"depth":201,"text":1696},{"id":57,"depth":201,"text":58},{"id":2118,"depth":201,"text":2119},{"id":2139,"depth":201,"text":2140},{"id":2146,"depth":201,"text":2147},{"id":1757,"depth":201,"text":1758},"UI design","\u002Fimages\u002Fwork\u002Fkongkong-interface\u002Findex-desktop.png","A responsive, mobile-first interface for a student crowdfunding platform.",[],{},[],24,"\u002Fprojects\u002Fkongkong-interface","UI Designer",{"title":2096,"description":2196},"projects\u002Fkongkong-interface",[2206,1466,2207,2208],"Interface","Responsive","Mobile first","7ty2XTsE0k_PYbnXgMogaka3PYjXeGuXzmreOcJF_2Q",{"id":2211,"title":2212,"architecture":1193,"body":2213,"category":2242,"company":1193,"contribution":1193,"cover":2243,"description":2244,"draft":217,"extension":218,"featured":217,"links":2245,"meta":2246,"metrics":2247,"navigation":234,"order":2248,"path":2249,"role":2250,"seo":2251,"stem":2252,"technologies":2253,"timeline":1193,"type":1839,"year":2257,"__hash__":2258},"projects_en\u002Fprojects\u002Fdigital-art.md","Digital Art",{"type":32,"value":2214,"toc":2238},[2215,2218,2221,2225,2228,2231,2235],[40,2216,2217],{},"A collection of personal illustration work.",[40,2219,2220],{},"Illustration is where I practise the things that later show up in interface and brand work: reducing a subject to the few shapes that make it recognisable, choosing a limited palette, and knowing when to stop rendering.",[35,2222,2224],{"id":2223},"four-pieces-four-approaches","Four pieces, four approaches",[185,2226],{":images":2227},"[{\"src\":\"\u002Fimages\u002Fwork\u002Fdigital-art\u002Fzuko.png\",\"alt\":\"Painted illustration of a swordsman in red robes\",\"caption\":\"Painterly — loose brushwork, a single dark backdrop to push the red figure forward.\"},{\"src\":\"\u002Fimages\u002Fwork\u002Fdigital-art\u002Fishaq.png\",\"alt\":\"Illustrated portrait of a young man thinking\",\"caption\":\"Line and cel shading — clean outlines, flat shadows, hand-lettered name.\"},{\"src\":\"\u002Fimages\u002Fwork\u002Fdigital-art\u002Fhend.png\",\"alt\":\"Vector portrait in an orange jacket on an orange background\",\"caption\":\"Vector portrait — a near-monochrome orange palette with one glowing circle for depth.\"},{\"src\":\"\u002Fimages\u002Fwork\u002Fdigital-art\u002Fmascot.png\",\"alt\":\"Flat cartoon character with arms crossed\",\"caption\":\"Flat character — big head, simple shapes, a mascot-style figure.\"}]",[1708,2229],{":steps":2230},"[{\"title\":\"Silhouette first\",\"text\":\"Each piece starts from a pose that reads in solid black — if the silhouette works, the details are easy.\"},{\"title\":\"Limit the palette\",\"text\":\"One dominant hue per piece (red, green, orange, blue) keeps the image calm and the subject clear.\"},{\"title\":\"Match finish to purpose\",\"text\":\"Painting for a mood, vector for portraits that need to scale, flat shapes for a character that has to work small.\"}]",[35,2232,2234],{"id":2233},"original-sheets","Original sheets",[185,2236],{":images":2237},"[{\"src\":\"\u002Fimages\u002Fwork\u002Fdigital-art\u002Fdigital-art-1.png\",\"alt\":\"Digital illustration 1\"},{\"src\":\"\u002Fimages\u002Fwork\u002Fdigital-art\u002Fdigital-art-2.png\",\"alt\":\"Digital illustration 2\"}]",{"title":200,"searchDepth":201,"depth":201,"links":2239},[2240,2241],{"id":2223,"depth":201,"text":2224},{"id":2233,"depth":201,"text":2234},"Illustration","\u002Fimages\u002Fwork\u002Fdigital-art\u002Fhend.png","Four pieces of personal illustration across two hands — loose digital painting and clean vector portraits.",[],{},[],25,"\u002Fprojects\u002Fdigital-art","Illustrator",{"title":2212,"description":2244},"projects\u002Fdigital-art",[2254,2255,2256],"Digital painting","Vector","Character design",2018,"EuTkVekIbFgklymNRP7eXjjsOnde2pcvHItxof8_9fA",1793701912970]