Software Engineer · Licensed Electronics Engineer · Remote, Philippines

Cherljohn Neo
Rondovio

I build the software that sits between systems that were never designed to talk to each other: a POS and a WiFi controller, a Discord gateway and a Postgres database, four ad platforms and one spreadsheet. Then I ship the apps that come out the other side.

On the Microsoft Store
1 app
Scripts in daily production
30
Client servers automated
20
Platforms integrated
8

About

Most of what I build runs unattended against live business systems, where a bad assumption costs real money and there is no staging environment to hide in.

That has shaped how I work. I write the unglamorous safeguards first: idempotency keys so a retried sale never mints a second voucher, ordering rules so a script can never wipe a spreadsheet before it knows it can refill it, blank-by-default targets on anything destructive so it cannot run until a human consciously picks one. I pick architecture to fit real constraints rather than to fit a diagram: a free tier's instance-hour budget, a controller's hard voucher ceiling, a platform with no API at all.

I work across Python and JavaScript/TypeScript: browser automation and Google Sheets pipelines on one end, Electron desktop apps, Capacitor Android builds, Cloudflare Workers and Postgres on the other. I document as I go, because most of these systems get handed to someone else to run.

Experience
Building and running production tooling for a media-buying agency since April 2025
Licences
Electronics Engineer (ECE) & Electronics Technician (ECT), PRC 2026
Education
BS Electronics Engineering, Mindanao State University, 2020–2024
Recognition
4th Runner-up, Datathon at the IECEP National Students' Summit, 2023
Languages
English (professional) · Filipino · Cebuano · Hiligaynon

Selected Work

Six projects, grouped by what each one demonstrates. Most of these run against live production systems for real clients, so what follows is the architecture and the thinking behind each one rather than a tour of the code.

01

Shipped Products

End-user apps built, packaged, signed and released.

Flicker reviewing a photo in full screen with keep and delete controls
Flicker Delete Mode
Flicker session summary overlay

Flicker

Published

Desktop app · Windows · Electron · Solo build

A local media triage app. One photo or video fills the screen, you make one decision (keep, delete, or move), and the next file appears. Nothing leaves the machine.

The problem

Camera rolls and download folders accumulate thousands of near-duplicate photos and screenshots. File explorers are built for browsing, not for deciding, so the cleanup never happens.

What I built

A full-screen, swipe-style flow driven by arrow keys, on-screen buttons or a swipe. Deleted files move to a _deleted subfolder rather than vanishing, every action is undoable, and each session ends with a tally of what was kept, moved and deleted.

Engineering worth noting
  • Video seeking that actually works. A custom flicker-media:// protocol in the Electron main process serves media with HTTP Range support, so scrubbing a large video is instant instead of waiting on a full file read.
  • Locked-down renderer. contextIsolation and sandbox both on, with exactly four IPC calls exposed through a contextBridge preload. The main process is the only thing that ever touches the filesystem.
  • No framework, no build step. The renderer is a single static HTML/CSS/JS file, which is why the packaged app is small and starts instantly.
  • Three release channels from one codebase. An MSIX package for the Microsoft Store, an NSIS installer, and a portable single .exe.
  • Electron
  • Node.js
  • JavaScript
  • IPC / contextBridge
  • electron-builder
  • MSIX
Suaver app icon
Suaver brand kit: app icons and adaptive Android assets generated from a single source

Suaver

In development

PWA + Android · Vanilla JS · Capacitor · Solo build

A budgeting app that splits your money into days and shows one number: what you can spend today without touching tomorrow.

The problem

Budgeting apps report in months. People spend in days. The useful question is not "how much is left this month." It is "how much can I spend right now and still be fine."

What I built

A no-backend, no-account app; all state lives on the device. It runs as a web page, installs to the home screen, and ships as an Android build with a home-screen widget.

Engineering worth noting
  • Timezone-correct date maths. Real instants are mapped into a pseudo-UTC domain carrying the user's chosen wall clock, so all calendar arithmetic runs on UTC getters and behaves identically regardless of the browser's own timezone. Every function is pure and takes the timezone as an argument.
  • Storage as a driver stack. A repository layer owns the shape on disk (schema version and migrations), while a driver layer owns the place, picking the first available of localbridgememory and falling back to memory if one fails mid-session.
  • Strict layering. The core has no DOM and no rendering, so the money, period-rollover and timezone logic is unit-testable in plain Node. Dependencies only ever point downward.
  • Tests that don't rot. The suites assert relative to today rather than against hard-coded dates, so they stay valid as real time moves on.
  • A theme system from two numbers. Six colours × two modes, where a theme sets only a surface hue and an accent hue and the stylesheet derives the rest. The one exception is the signature brand palette, which stays literal so it can never drift as the generator changes.
  • JavaScript (ES modules)
  • Vite
  • Capacitor
  • Android
  • PWA
  • node:test
  • CSS design tokens
02

Systems & Integrations

Services that keep running when nobody is watching.

Cafe voucher service architecture A point-of-sale system and a cashier page both call the voucher service, which talks to the Omada controller, a thermal printer, and a background janitor process. Loyverse POS receipts webhook Cashier page plain HTTP Voucher Service Omada controller site A · site B Thermal printer ESC/POS · port 9100 Janitor purges spent codes idempotencyKey = receipt line id a retried sale returns the same code, never a second voucher

Cafe Voucher Service

Middleware · Node 22 + TypeScript · Client project

Middleware that issues a WiFi hotspot voucher at the exact moment of sale, prints it, and quietly deletes spent ones, replacing a manual loop the cafe staff were running by hand every week.

The problem

The old routine: generate 500 vouchers, print them, hand them out, hit the controller's hard 5,000-voucher ceiling, delete the used ones by hand, and generate another batch. Every step manual, and the ceiling turned into a full stop mid-shift.

What I built

A small service between the POS and the TP-Link Omada controller. One endpoint issues a code for a sale and returns a ready-to-print slip; a background janitor purges spent vouchers so the cap is never reached. It covers two sites, plan lookups for the POS button layout, and reprints for lost slips.

Engineering worth noting
  • Idempotency as the core design constraint. The POS sends the receipt line id as an idempotency key, so a timeout-and-retry returns the same code rather than minting a second voucher. That matters because Loyverse delivers receipt webhooks twice as a matter of course.
  • A simulated controller. The whole flow runs end to end with no hardware and no cloud account, so development and the test suite never touch a live cafe. Going live is one environment variable plus a documented verification pass.
  • Tested against failure modes, not the happy path. The suite covers the 5,000-voucher cap recovery, duplicate webhook delivery, POS retries, and an internet outage mid-shift.
  • Zero runtime dependencies. It runs on stock Node 22 with nothing to install on the cafe's machine, so there is one less thing to break at 7am. Playwright appears only in the separate live-ops tooling.
  • Direct ESC/POS printing to a network thermal printer over raw TCP, with the slip layout verified against a real 58mm reference capture.
  • Node.js 22
  • TypeScript
  • REST API design
  • Webhooks + HMAC
  • TP-Link Omada API
  • ESC/POS
  • Playwright
  • node:test
Discord bot cloud stack Discord traffic splits into a Cloudflare Worker for slash commands and a Render service holding a persistent gateway connection, which writes to Neon Postgres and mirrors to Google Sheets. Discord one application HTTPS POST gateway socket Cloudflare Worker /onboard command never sleeps Render · one service voice / camera audit join alerts one client, two handlers Neon Postgres + Google Sheets mirror Config mirror 60s refresh, no redeploy ~750 free instance-hours vs a ~730 hour month → one service, not two

Discord Bot Cloud Stack

24/7 in production

Distributed service · Python · Cloudflare Workers + Render + Neon

Migration of a media-buying agency's Discord automation off a Windows tray app on somebody's desktop and onto always-on cloud infrastructure, running entirely on free tiers.

The problem

Three bot behaviours the agency depends on (client server onboarding, voice and camera activity auditing, and new-member alerts) lived in a desktop script with a tray icon. If that PC slept, the agency's tooling stopped, and the audit trail was a text file nobody could query.

What I built

A two-host deployment behind a single Discord application, with the audit trail moved into a real database that reporting reads directly, so the report is always current with no manual export step.

Engineering worth noting
  • Split by hosting requirement, not by feature. The /onboard command only needs Discord to reach an HTTPS URL, so it went to Cloudflare Workers, which never sleeps, so the team never sees "application did not respond" behind a 60-second cold start. Voice state changes and member joins have no webhook and no REST endpoint on Discord's side; they arrive only over a persistent gateway socket, which is precisely why that half cannot be serverless.
  • Two features, one process, on purpose. The free tier gives roughly 750 instance-hours against a ~730-hour month, so a second always-on service would not fit the budget. Both gateway features became two sets of event handlers on a single client.
  • Blast-radius control. In a shared process, one server's missing config used to raise SystemExit and take the voice audit down with it. Now a missing channel disables that one feature for that one server, and everything else keeps running.
  • Config without redeploys. Server, prefix and buyer mappings are pulled from a mirror on a 60-second refresh, so the ops team edits JSON and the change lands on its own.
  • A migration with a way back. The original desktop scripts were left untouched and documented as manual fallbacks, with an explicit runbook rule: suspend the cloud service first, or every event gets recorded twice.
  • Python
  • discord.py
  • Cloudflare Workers
  • Render
  • Neon Postgres
  • SQL
  • Google Sheets API
  • WebSockets
03

Automation & Data

Pipelines that replace hours of manual work every morning.

Daily refresh orchestration One command runs three independent scraper lanes in parallel; they join, and a final snapshot step runs only if every lane succeeded. One command the whole morning refresh Shopify partner stores Automize client dashboard Discord capacity + drives join: did every lane pass? ALL DATA snapshot skipped if any lane failed a half-rebuilt source never overwrites a good copy

Media-Buying Ops Toolkit

Daily in production

Automation suite · Python · 30+ scripts · Agency-wide

The internal tooling for a media-buying agency: revenue and ad analytics pulled from four platforms into Google Sheets, Discord client-server reporting and maintenance, and a single command that runs the whole morning refresh.

The problem

Reporting spanned Meta Ads, Shopify, Omnisend and Postscript, plus a Discord workspace of client servers, each with its own login, its own export and its own format. Hours of copy-paste before anyone could look at a number.

What I built

A toolbox of independently runnable scripts sharing one config layer, plus an orchestrator that runs the daily refresh in parallel lanes and reports on all of them at once. Where a platform offers an API I use it; where it does not, a persistent browser session drives the real UI.

Engineering worth noting
  • A dependency-aware parallel run. Three lanes are genuinely independent and run concurrently. The fourth step is a snapshot of what the others just wrote, so it waits for the join, and is skipped entirely if any lane failed, so a half-rebuilt source can never be published over a good copy. The run summary names the exact re-run command.
  • An ordering rule learned the hard way. A scraper that cleared its sheet and then discovered it was logged out emptied 1,104 rows and wrote nothing back. The fix generalised: everything that can abort a run (the session check, the client list fetch, all of it) happens before the destructive clear, never after.
  • Safety interlocks on destructive tools. The scripts that delete channels or messages ship with a blank target by default. They cannot run until a human consciously names one; the blank is the interlock, not an oversight.
  • Format-preserving restores. Sheets snapshots are written raw rather than re-parsed. Otherwise 16-digit ad-account ids come back as 1.08E+15 and phone numbers as #ERROR!.
  • Documented for handoff. A single orientation document plus per-area runbooks cover what each script does, which decisions look wrong but are deliberate, and what to do when the cloud stack is down.
  • Python
  • Playwright
  • Google Sheets API
  • Meta Marketing API
  • Shopify API
  • Omnisend
  • Postscript
  • Concurrency
  • Service accounts
04

Also Built

Smaller projects, prototypes and one-off client work.

Split

React 19 · TypeScript · Tailwind 4

A bill-splitting web app built from a design handoff. Written as a fully commented codebase alongside a "React for Python developers" guide, deliberately structured as a teaching artefact as well as a working app.

  • React
  • TypeScript
  • Vite
  • Tailwind

Captive WiFi Portals

Two cafe venues · HTML/CSS · Python

Branded captive-portal login pages for two venues, plus a Python generator that turns a raw voucher export into a print-ready sheet of cut-out codes. It was the manual predecessor to the voucher service above.

  • Python
  • HTML/CSS
  • Omada portal

Raspberry Pi Camera Server

Python · Embedded Linux

A streaming camera server for a Raspberry Pi with a companion viewer client and link-quality probing tools, built to get a live feed off a headless board over an unreliable connection.

  • Python
  • Raspberry Pi
  • Video streaming

Trading Simulation

Python · Self-directed

A market simulation written to pressure-test strategy logic against generated price series, part of a habit of building small things to understand a domain properly rather than reading about it.

  • Python
  • Simulation

Skills

Languages

  • Python
  • JavaScript (ES modules)
  • TypeScript
  • SQL
  • HTML & CSS

Application

  • Node.js
  • Electron
  • React
  • Vite
  • Capacitor / Android
  • Progressive web apps

Cloud & Infrastructure

  • Cloudflare Workers
  • Render
  • Neon Postgres
  • Google Cloud service accounts
  • Free-tier capacity planning

Integrations

  • REST API design
  • Webhooks & HMAC signing
  • Meta Marketing API
  • Shopify
  • Discord gateway + HTTP
  • Google Sheets API
  • TP-Link Omada
  • ESC/POS hardware

Automation

  • Playwright browser automation
  • Scheduled & unattended jobs
  • Idempotency & retry design
  • Job orchestration and concurrency
  • Data pipelines into Sheets

Practices

  • Testing failure modes, not happy paths
  • Simulators for hardware-dependent work
  • Runbooks & handoff documentation
  • Safety interlocks on destructive tooling
  • Git

Contact

Always glad to talk about this kind of work: automation, integrations, backend services, or app development. If something here is relevant to what you are building, get in touch.