Home / Writing
Notes from building things
Write-ups of my side projects by Vu Minh Hoa: how they work, the trade-offs behind them, and what I would change.
These posts are drafted with AI assistance from the projects’ own source code and documentation.
01 / 9 posts
Backend, data & infrastructure
Stream processing, audit logs, real-time sync, search and the server the projects run on.
One Keycloak for several apps: realms, audiences and quiet failures
Self-hosted Keycloak for several side projects: realm per app, checking aud, deleted users recreated by live tokens, refresh races and a startup trap.
· 10 min read
Exactly-once doesn’t come for free: Kafka, Flink and ClickHouse
Where an event pipeline loses or double-counts data: idempotency keys claimed too early, sink buffers outside checkpoints, and materialized views.
· 9 min read
A tamper-evident audit log in PostgreSQL with hash chains and HMAC
Building an audit log whose history can’t be quietly rewritten, layer by layer, plus detecting truncation and clearing IPs without breaking the chain.
· 7 min read
Server-Sent Events in Spring Boot: Redis Pub/Sub and slow clients
Real-time sync with SseEmitter: cookie auth for EventSource, fan-out across instances, a bounded write pool that drops hints, and when to consider WebFlux.
· 8 min read
Time in Apache Flink: watermarks, idle partitions, state TTL and replay
Silently dropped late events, a quiet partition stalling every window, TTL on the wall clock, and processing-time timers that break deterministic replay.
· 7 min read
Vietnamese search in Elasticsearch: diacritics, n-grams and filter order
Accent-insensitive Vietnamese search: asciifolding, why stopwords must come before it, n-grams for partial codes, search_after paging and rebuildable indexes.
· 7 min read
Tracking Vietnamese news trends with embeddings, HDBSCAN and an LLM
How I group articles from ~95 Vietnamese news feeds into topics, score which ones are rising or fading, and have an LLM explain why.
· 9 min read
Modeling hospital procurement bidding: lessons from my graduation project
A ~30-step public bidding process in software: one record from proposal to acceptance, JSON phases with defaults, and acceptance as one transaction.
· 10 min read
Self-hosting side projects: principles and silent failures
Infrastructure in git, a small attack surface, canary deploys, and the bugs that never raised an error: pipefail, Actions concurrency, Docker bind mounts.
· 8 min read
02 / 6 posts
Local-first apps
Apps that keep working offline: sync protocols, IndexedDB at scale and PWAs on iPhone.
Local-first PWA sync: last-writer-wins done carefully
Offline-first sync with IndexedDB: idempotent pushes, tombstones, seq order with advisory locks, server-corrected clocks, and data shaped to avoid conflicts.
· 8 min read
Four bugs that silently broke RxDB sync, and how they were fixed
Rows stuck at version 0, a client-only column, a migration that never finished, and a resync loop: sync failures that never threw an error.
· 10 min read
A large tree in IndexedDB with RxDB: indexes, trigram search and lazy loading
Why a nullable parent ID made a 61-node query take 19.6 s, and how a shadow index, diacritic-free trigrams and virtualization fixed it.
· 8 min read
An installed PWA on iPhone: safe updates, deploys and iOS details
Updates that wait for the user, deploys that broke open tabs, a launch logo measured on the device, zooming fields, and Web Push for a local-first app.
· 8 min read
Parsing money the way Vietnamese people type it: 2,5tr, 500k and 1tr+500k
Units like tr and tỷ, a dot that means two things, sums typed as in Excel, a caret that stays put, and the missing + key on phone keypads.
· 8 min read
Vietnamese lunar calendar in JavaScript: why 5 test dates weren’t enough
Why a popular lunar library disagrees with the Vietnamese calendar on 3.48% of days (UTC+8 vs UTC+7), found by comparing 40,542 days instead of 5.
· 8 min read
03 / 5 posts
Security & macOS
End-to-end encryption and a macOS monitor built on Endpoint Security.
DarkSword on iPhone: the six-bug chain, P7, and which iOS is safe
How the DarkSword iOS exploit chain works, what the P7 variant steals, which iOS versions are safe, and what to do if you can’t update yet.
· 10 min read
Building an end-to-end encrypted chat app with libsodium
The key design behind an E2EE chat: per-chat keys sealed to each member, signed message chains, and the general limits of detecting a cheating server.
· 8 min read
Endpoint Security on macOS without the entitlement: eslogger and Swift
Reading eslogger from a root Swift helper: Full Disk Access, a one-pass Aho–Corasick prefilter on raw JSON, rules scoped to the program, and self-noise.
· 8 min read
Making a Mac security monitor hard to silence
Telling a reboot from kill -9, a Telegram bot that can delete its own alerts, processes that watch each other, an append-only log and a dead man’s switch.
· 8 min read
From a polling Bash script to an event-driven Swift daemon on macOS
How a macOS security daemon went from ~4.5% to ~0.4% of a core: APIs instead of forks, FSEvents and IOKit, ctime prefilters, and a netstat that hides sockets.
· 8 min read
04 / 2 posts
Web & open source
An SEO analysis library and the rules behind its scores.
Forking a GPL library and publishing it on npm without losing upstream
Forking Yoast’s yoastseo: GPL notices, a no-change merge that makes syncs three-way, a monthly filter-repo sync, and rules that keep conflicts rare.
· 8 min read
Auditing an SEO checker against Google’s docs, and silent scoring bugs
Tracing every rule of an open-source SEO checker to Google’s guidance, what changed without a source, and score bugs that never threw an error.
· 9 min read