Rukon
Blog

Notes from building real systems.

Notes on production and operations systems, full-stack development, AI applications and web development, written from real project work in Cyberjaya rather than from tutorials.

  1. Building Real Systems

    Installing Drivers From Official Sources Only: Allow-Lists, Catalogue Hashes and Authenticode

    How the BBTech Laptop Inspection Tool finds, downloads, installs and verifies a driver for a refurbished laptop without ever running an unsigned or unofficial package, and why its status vocabulary has no word for a success it did not confirm.

    4 min read

  2. Full-Stack Development

    Google Sign-In Without a Client Library: Server-Side PKCE and Grants Read on Every Request

    RPOMS added Google sign-in through its Supabase project's provider with no client library in the browser bundle. Google proves who someone is and grants nothing; a Super Admin grants access per service and capability, and revocation takes effect on the next request.

    3 min read

  3. Full-Stack Development

    Sorting on the Column the Index Serves: 160 ms to Under 1 ms at 250,000 Routers

    The RPOMS Registry page sorted on a text copy of the timestamp it selected, so the index on the real column was never used. Measured on an isolated 250,000-row copy, the fix is one ORDER BY and a read deadline that keeps the page honest when a query is slow anyway.

    3 min read

  4. Full-Stack Development

    One Live Record per Router per Session: Partial Unique Indexes Instead of Per-Scan Locks

    A barcode scanner can fire the same serial twice in a few milliseconds, and two workstations can scan the same router at once. RPOMS's Refining workstation catches both with one partial unique index, and decides whether to print from what the save recorded.

    3 min read

  5. Building Real Systems

    Refusing Runtime DDL on Production: Schema Stamps, a Gate, and Schema-Only Migrations

    RPOMS used to build its own tables on a cold start. On a shared production database that is a race and a risk, so the application now refuses to alter production schema, and a release ships as ordered, schema-only migration files with rollback blocks.

    4 min read

  6. Full-Stack Development

    Sending Labels From One Web App to Another Tab: BroadcastChannel, COOP and window.opener

    How RPOMS sends a router label to the Print Engine tab that holds the Bluetooth printer: why a hidden iframe could never work across sites, why one header had to be removed from one path, and what a lost answer must say.

    5 min read

  7. AI & Automation

    Offline Receipt OCR on Android: On-Device Google ML Kit Text Recognition with Jetpack Compose

    How SpenDrop's native Android engine parses payment receipts and merchant summaries offline on device using Google ML Kit, Jetpack Compose, and Room SQLite without third-party cloud APIs.

    3 min read

  8. Building Real Systems

    Extracting Hardware Serial Numbers Over LAN: UPnP, CSTECGI, and SNMP Across Telco Router Vendors

    How the BBTech WiFi Router Diagnostic Tool extracts authentic factory serial numbers directly over an Ethernet connection without an external barcode scanner, handling Kaon, Huawei, and TP-Link routers.

    2 min read

  9. Building Real Systems

    Excluding a Damaged Display Zone via the Windows AppBar API (SHAppBarMessage)

    How to salvage a laptop or monitor with a broken, flickering line of pixels by registering a hidden Windows Application Desktop Toolbar to shrink the system work area at runtime.

    2 min read

  10. Building Real Systems

    Why Hardware Identity Matters: How Generated Stock Prefixes Concealed Duplicate Refurbishments in ITMS

    An architectural audit of enterprise refurbishment systems: why generating sequential stock prefixes like 'HP1' creates phantom inventory, and how binding to immutable SMBIOS hardware serials provides a tamper-proof audit trail.

    3 min read

  11. Full-Stack Development

    Sub-Millisecond Saves: Designing a Local-First Outbox and Sync Engine in SwiftData

    How SpenDrop achieved an on-device save latency of 0.240 ms in SwiftData while synchronising in the background with a remote Supabase PostgreSQL backend using the persistent outbox pattern.

    3 min read

  12. Building Real Systems

    Connection-Pool Exhaustion Under Serverless Scale: Investigating Supavisor and Vercel in Production

    A postmortem of production incident INC-2026-10-11-01: why Vercel serverless functions saturated Supavisor transaction pool connections during a warehouse shift change while CPU was under 5%, and how we recovered with zero data loss.

    4 min read

  13. Full-Stack Development

    The Wrong Supabase Key Doesn't Fail. It Returns 200 and Zero Rows.

    A publishable Supabase key in a server slot meant for a secret one: every read succeeded with no rows, the dashboard showed confident zeros, and the health check said all was well.

    3 min read

  14. UI/UX & Product

    Writing a Page an AI Answer Engine Can Quote Correctly: GEO on a Locked Design

    Implementing a GEO requirement on a locked design: test the questions visitors ask, make answers self-contained, attribute claims, and escalate contradictions.

    6 min read

  15. Full-Stack Development

    The Service Worker Was Active and the Cache Was Empty: A Workbox Duplicate-Entry Bug

    An offline PWA that registered its service worker, cached nothing, and failed silently. The cause was one file listed twice in the precache manifest by vite-plugin-pwa's includeAssets.

    3 min read

  16. AI & Automation

    The Plan Said RAG. The Papers Said Send the Whole Thing.

    ResearchForge was planned as a retrieval pipeline. Measured papers fit whole in the context window, so it sends the full text and only chunks a genuinely oversized document.

    4 min read

  17. Full-Stack Development

    Production Broke and Nothing Had Changed: A Paused Free-Tier Database

    Admin sign-in returned 503 and nothing was being saved, with no deploy and no config change. One credential-free request that tells a database outage from wrong credentials.

    3 min read

  18. AI & Automation

    What Moving Self-Hosted Inference to a Server Will and Won't Fix

    A migration plan, not a result: why moving RPOMS AI's model from a laptop to a dedicated server would improve availability but not accuracy, and the gates it must pass first.

    4 min read

  19. Building Real Systems

    Versioning an Operational Spreadsheet Like Software

    A stock tracker's Change History sheet as a release log: eight iterations before go-live, a 1.x line after, user-requested versions, and what an in-file changelog cannot give you.

    5 min read

  20. Building Real Systems

    Vercel or a Self-Hosted Ubuntu Box? How I Chose Hosting App by App

    Eight deployed apps, three hosting shapes: Vercel for pages and serverless APIs, a self-hosted Ubuntu box for a stateful API, and a hybrid for a model Vercel can't run.

    6 min read

  21. Full-Stack Development

    Why My VBA Maps Columns by Header Name, Not Column Number

    One workbook held both approaches: event macros with hard-coded column numbers that drifted as columns were added, and an update macro that finds columns by header text. The difference.

    5 min read

  22. Full-Stack Development

    Two Ways I Use Supabase Row Level Security: Deny-All Behind a Server, or Per-Owner Policies

    Across five projects, RLS does one of two jobs: close the Data API while a trusted server does the work, or let Postgres enforce who owns each row. When to pick which.

    5 min read

  23. Full-Stack Development

    Theme-Specific Logos Without a Flash: Let CSS Pick, Not useTheme()

    A logo with an opaque white background became a white block on the dark theme. Swapping it in CSS on data-theme, not with useTheme(), fixed it on the first frame.

    3 min read

  24. Building Real Systems

    Testing Without Paid APIs or Hardware, and the Places Fakes Lied

    Fake LLM providers, a simulated label printer and an in-process Postgres keep my test suites free and offline. What each proved, and three places a fake fell short.

    5 min read

  25. Full-Stack Development

    Proving a PWA Boots Offline: A Headless Chrome Test Over the DevTools Protocol

    An automated test that installs a PWA under production headers, cuts the network at the protocol level, reloads, and checks the app still works, with no test framework beyond a WebSocket.

    5 min read

  26. Full-Stack Development

    Testing Real PostgreSQL SQL in Vitest With PGlite and the Real Driver

    No Postgres server, no Docker, and production off limits. PGlite behind a loopback socket let the real postgres.js driver run real SQL in Vitest and in CI.

    4 min read

  27. Full-Stack Development

    The Test That Calls Every Next.js API Route With No Session

    Five API reads in RPOMS typechecked and linted cleanly and were open to anyone. They were found by probing the built app, and now one test globs every route.ts and expects a refusal.

    4 min read

  28. AI & Automation

    Testing an LLM App Without Calling a Paid API

    538 tests for an LLM application, none of which call a paid model. FastAPI dependency overrides, a fake provider, generated PDFs, opt-in live tests, and where fakes stop telling the truth.

    4 min read

  29. Full-Stack Development

    SwiftData Migrations That Can't Lose Data: VersionedSchema, Pre-Upgrade Copies and a Safe Mode

    SwiftData's inferred migration silently dropped a table. How SpenDrop moved to VersionedSchemas, pre-upgrade copies and a safe mode that never deletes.

    6 min read

  30. Full-Stack Development

    Why Supabase Google Sign-In Landed on localhost With a Token in the URL

    Google sign-in on a custom domain returned users to localhost:3000 with an access token in the address bar. Two separate causes, the Site URL fallback and the implicit flow, and the fixes.

    4 min read

  31. Full-Stack Development

    Google Sign-In on iOS Through Supabase, With PKCE and No Google SDK

    Google sign-in on iOS through Supabase with ASWebAuthenticationSession and PKCE, no Google SDK or client secret, plus an identity bug RLS would reject.

    5 min read

  32. Building Real Systems

    Backing Up a Database on a Plan With No Backups, and a One-Way Staging Refresh

    The procedure and scripts I designed for a production Supabase database on the Free plan: a read-only JSON export, a restore that only targets staging, and an anonymising refresh.

    4 min read

  33. Full-Stack Development

    Structured Data for a Local Recycling Business: Organization, RecyclingCenter and an FAQPage That Matches the Page

    Turning a client's schema requirements into JSON-LD for a Malaysian e-waste service: Organization plus RecyclingCenter, and an FAQPage that mirrors the visible FAQ.

    5 min read

  34. Full-Stack Development

    Storing Uploaded Photos in Postgres bytea, Served Only to Admins

    Why RPOMS AI keeps inspection photos in a PostgreSQL bytea column instead of a bucket, how they are served only through an admin-guarded route, and when this stops being a good idea.

    3 min read

  35. Full-Stack Development

    Stopping Vercel Preview Deployments From Touching the Production Database

    Every preview of RPOMS carried the production connection string. A guard in code now refuses the pairing, answers 503 with the reason, and can be checked from outside.

    5 min read

  36. Building Real Systems

    A Stock Request Portal With a State Machine and an Event Log

    The lifecycle behind the RPOMS Ecommerce portal: a transition table, terminal states, a void that reverses, version-checked edits and an event per step.

    5 min read

  37. Full-Stack Development

    Out-of-Order Responses on Filter Changes: Only the Newest Request May Write

    Filters that apply on change put several fetches in flight, and the slow broad one often lands last. A ticket per request in a React ref keeps the screen answering the current question.

    3 min read

  38. Building Real Systems

    Splitting RM 10 Three Ways: Integer Sen and the Largest-Remainder Method

    Floating-point money drifts and naive splits lose a sen. Integer sen at one boundary and the largest-remainder method, so shares always add up.

    4 min read

  39. Full-Stack Development

    Sorting Apple Vision Text Into Lines Without Crashing Swift's Sort

    VNRecognizeTextRequest returns boxes, not lines. Sorting them top to bottom and left to right with a comparator Swift's sort can trust.

    3 min read

  40. Full-Stack Development

    Sharing One Supabase Project Between Two Apps Safely

    A second app inside an existing Supabase project: prefixed tables, RLS on with no policies, revoked grants, server-only access and an admin check for a shared user list.

    4 min read

  41. AI & Automation

    Shadow-Testing a Replacement Model With Next.js after(), Without the User Waiting

    How RPOMS AI is built to run a candidate model on real requests after the response is sent, record whether it agreed, and never show it. The lifecycle around it, and its limits.

    4 min read

  42. Building Real Systems

    Detecting a Device Model From Its Serial Number With Prefix Rules

    How RPOMS and its print engine tell a router's model from its serial: prefix and length rules stored as data, longest prefix first, unknowns flagged.

    5 min read

  43. Malaysia & Cyberjaya

    Telling the Sender Bank From the Recipient on a Malaysian Transfer Receipt

    A CIMB to Maybank transfer receipt names both banks. Reading the receipt's structure to attribute the payment to the bank that actually sent it.

    5 min read

  44. Full-Stack Development

    Self-Hosting a Node and PostgreSQL Service With nginx and systemd on Ubuntu

    The deployment behind print.rukon.dev: one origin for a PWA and API, a hardened systemd unit, atomic releases, nginx header gotchas and a backup design.

    7 min read

  45. Full-Stack Development

    Baseline Security Headers in Next.js, and Why the CSP Waited

    Adding five response headers to a Next.js site that served none, why the Content-Security-Policy was deliberately deferred, and a nonce-free CSP on another app.

    4 min read

  46. Full-Stack Development

    Security Headers for a Web Bluetooth PWA, Pinned by a Test

    The CSP, Permissions-Policy and COOP for a PWA that drives a Bluetooth printer, why each source is there, a separate policy for the API, and a test that keeps nginx and the app in step.

    5 min read

  47. Full-Stack Development

    When the Code Ships Before the Migration: Degrading One Schema Level at a Time

    Selecting a column that a pending migration adds made PostgREST fail every library read. The fix degrades one migration tier at a time, so deploy order stops mattering.

    4 min read

  48. Building Real Systems

    Schema Setup on Cold Start: One Statement, One Winner, and a Building Sentinel

    Serverless instances that create tables on first use race each other and hold exclusive locks. How RPOMS claims the schema build with one SQL statement, and the bug in the first version.

    4 min read

  49. AI & Automation

    Running Qwen2.5-VL 7B on an Intel Iris Xe With Ollama and Vulkan: 119 s to 41 s

    Setting up a 7B vision model on a Windows laptop with no discrete GPU: enabling the Iris Xe under Ollama, where the time actually goes, and what the GPU profile showed.

    5 min read

  50. UI/UX & Product

    Adding Arabic (RTL) to a Next.js Dashboard Without Translating the Whole App

    Publishing the RPOMS dashboard in Arabic: a typed dictionary that fails the build, dir on one wrapper not <html>, an LTR chart, and Latin digits.

    4 min read

  51. UI/UX & Product

    Defaults Are Claims: Removing Placeholder Numbers That Looked Like Measurements

    A 75% tank, a 10 km/L economy, a hardcoded user id: defaults in DriveKeep that rendered as real data, what replaced them, and the same rule in SpenDrop.

    5 min read

  52. Developer Journey

    Working Through a 44-Finding Code Audit, Six of Them P0, Without Losing Data

    How I worked through a forensic audit of a live operations system: the four root causes behind 44 findings, a second pass that caught my own regressions, and what I chose not to change.

    5 min read

  53. Full-Stack Development

    Rate Limiting a Public Endpoint on Serverless, Keyed by an HMAC of the Address

    Two layers for an anonymous upload endpoint on Vercel: an honest in-memory burst limiter, and a durable hourly count in Postgres keyed by an HMAC so the address is never stored.

    4 min read

  54. AI & Automation

    A Qualification Gate: Computing What a Model Is Allowed to Decide From Its Own Results

    Instead of trusting a model or not, RPOMS AI computes per verdict and per criterion what the model has earned the right to say, from a reference run. The policy, the code and the trade-off.

    4 min read

  55. Full-Stack Development

    Promise.race Timeouts Don't Cancel Queries, and That Emptied My Connection Pool

    A read deadline built on Promise.race walks away from a query that keeps running and keeps its pooled connection. How that fed on itself on Vercel, and the bounds that fixed it.

    4 min read

  56. Full-Stack Development

    A Production Write Lock That Fails Safe: Only Named Modules May Write

    How RPOMS keeps finished modules from writing in production until sign-off: a middleware lock that is on by default in production and an allowlist matched by path segment.

    4 min read

  57. Full-Stack Development

    postgres.js Dropped the Microseconds From My timestamptz Parameter

    A revision check refused every save because a bound timestamptz went through a JavaScript Date and lost its microseconds. One extra ::text cast fixed it.

    3 min read

  58. Full-Stack Development

    postgres.js Stored My JSON Arrays as Strings in a jsonb Column

    Writing JSON.stringify(x)::jsonb through postgres.js encodes the value twice, so a jsonb column holds a string, not an array. The symptom, the sql.json() fix, and handling rows already stored.

    3 min read

  59. Full-Stack Development

    Bulk Inserts Past PostgreSQL's 65,535 Bind-Parameter Limit: unnest and Chunks

    A multi-row VALUES insert with six parameters per row failed outright above 10,922 rows. Replacing it with unnest over array parameters, chunked, and why the import is not one transaction.

    3 min read

  60. Full-Stack Development

    Porting a Static Page to Next.js Without Visual Drift

    Rebuilding a finished page in Next.js 16 and Tailwind 4 so it looks identical: the font fallback, image optimiser and class-conflict traps, and how drift was checked.

    5 min read

  61. Developer Journey

    Planning a University Project Like a Real One: Milestones, Risks and a Decision Log

    The first commit of ResearchForge had no code: a plan with milestones, a risk register, a definition of done and numbered decisions. What that structure caught, and where the plan was wrong.

    5 min read

  62. Building Real Systems

    Apple Pay Is Not a Bank: Payment Channels, Funding Accounts and Reconciling Double Records

    One purchase can arrive as an Apple Pay tap and again as a bank record. Separating how you paid from where money came from, and merging the duplicate.

    6 min read

  63. AI & Automation

    One Pydantic Schema, Two LLM Vendors: Native Parsing vs JSON Mode

    The same Pydantic models drive structured output from Anthropic's native parsing and Groq's JSON mode. Forbidding extra fields, catching truncation, and validating instead of repairing.

    3 min read

  64. Building Real Systems

    Preview and Commit From the Same Plan: Stock Transfers You Can Reverse Exactly

    In RPOMS one pure function plans a stock transfer: the preview shows it, the commit re-runs it, and a void inverts the frozen executed plan exactly.

    5 min read

  65. Full-Stack Development

    One SQL Function for a Whole Analytics Dashboard

    Every figure on a small analytics dashboard, totals, a gap-free time series and ranked breakdowns, returned as one JSON document by one PostgreSQL function, in the owner's time zone.

    4 min read

  66. Building Real Systems

    Deletes That Don't Come Back: Tombstones and Last-Write-Wins in Offline Sync

    In offline sync, a deleted record comes back when another copy is pushed. DriveKeep's soft deletes, tombstone list and timestamp merge, and its clock problem.

    4 min read

  67. AI & Automation

    Reading an Odometer Photo: Preprocessing Variants, Tesseract.js and a Plausibility Check

    DriveKeep's web app reads four sharp-preprocessed variants of an odometer photo with Tesseract.js and ranks every candidate against the previous reading.

    4 min read

  68. Full-Stack Development

    Two Windows Bugs in a Node Launcher: "C:\Program" and a PATH That Hadn't Updated

    A one-command launcher for Ollama, a gateway and cloudflared broke on Windows twice: shell: true split the node path at its space, and a fresh install was not on the open terminal's PATH.

    3 min read

  69. Full-Stack Development

    Next.js Open Graph Metadata Replaces, It Doesn't Merge

    A child route that sets its own openGraph object silently drops the layout's og:image and og:locale. Why Next.js does that, and the helper this site uses to stop it.

    3 min read

  70. Full-Stack Development

    An Error Boundary That Retried Into the Outage: Backoff With Jitter

    A Next.js error.tsx that retries on its own is right for a wall display, and wrong if every open screen retries in lockstep. Longer waits, jitter and a slow interval that never stops.

    3 min read

  71. Full-Stack Development

    Refreshing a Supabase Session in Next.js 16's proxy.ts, and Not Authorising There

    Next.js 16 renamed Middleware to Proxy. Using proxy.ts only to refresh a Supabase session cookie for admin routes, while every page and API route checks authorisation itself.

    3 min read

  72. Building Real Systems

    Why My App No Longer Creates Indexes When It Deploys

    A plain CREATE INDEX in a cold-start schema build locks a busy table as a side effect of shipping code. Moving indexes to CONCURRENTLY migrations, and what the app still does.

    4 min read

  73. Building Real Systems

    Spending, Cash Flow and Who Owes Whom: Modelling Shared Bills in a Personal Finance App

    When a bill is shared, 'how much did I spend?' has three honest answers. SpenDrop's rules for spending, cash flow, refunds and balances.

    5 min read

  74. Building Real Systems

    Modelling a Multi-Stage Refurbishment Pipeline in Excel

    Following one laptop through an Excel stock tracker: a completeness gate at receiving, an automatic hand-off list, status derived from department ticks, e-commerce counts, and EDATE warranties.

    5 min read

  75. Building Real Systems

    Measured or Estimated: Calculating Fuel Economy Only From Full Tanks

    Dividing a top-up into the distance driven gives a meaningless economy figure. How DriveKeep measures km/L only from full tanks and labels estimates.

    5 min read

  76. Building Real Systems

    What Survives When an Excel Tracker Becomes a Web App

    Mapping an Excel stock tracker's sheets, formulas and macros onto the tables of the web system that replaced it: what carried over unchanged, and what had to become explicit.

    6 min read

  77. Malaysia & Cyberjaya

    Screens That Look Like Payments but Aren't: Parsing Malaysian Receipts Without Fake Expenses

    Balance, credit-limit and reward screens all show RM amounts. How SpenDrop rejects them, and the Malaysian receipt formats two of my parsers read.

    6 min read

  78. Full-Stack Development

    One Checked Value Instead of Two Booleans: Making a Bad Config Unrepresentable

    Two on/off flags allow a state with no correct behaviour: both off. Storing the enabled set as one CHECK-constrained value and validating the resulting state instead.

    3 min read

  79. Full-Stack Development

    Logout Still Worked for 30 Seconds: Token Caches on Serverless

    A token verification cache meant a signed-out session kept working for up to 30 seconds. Why evicting on sign-out does not fix it on serverless, and why the answer was a small measured bound.

    3 min read

  80. AI & Automation

    Logging Apple Pay Taps Automatically With an App Intent and a Wallet Automation

    An App Intent lets the Shortcuts Wallet automation hand each Apple Pay purchase to SpenDrop. The intent, its duplicate guard, and what iOS lets apps see.

    3 min read

  81. Building Real Systems

    A Written Conflict Policy for a Local-First Workstation App

    How an offline-first PWA writes locally first, syncs on its own timer with backoff, and resolves conflicts with a rule per data type: last writer wins, server wins, append-only, never synced.

    5 min read

  82. AI & Automation

    The Retries You Didn't Write: LLM Rate Limits and SDK Hidden Retries

    A client library's default retries turned one rate-limited analysis into twelve requests against a free tier of twenty. Removing requests, telling limits apart, and returning 429 with Retry-After.

    5 min read

  83. AI & Automation

    A Cross-Paper Literature Review Built From Stored Analyses, Not PDFs

    Building one LLM literature review across several saved papers by reading their stored analyses instead of re-sending every PDF. The trade-off, the size guards, and why partial results are refused.

    4 min read

  84. Full-Stack Development

    Keeping Your Email and Phone Off a Public Link Page Until Someone Asks

    A QR link page that never ships private contact details in its HTML or JavaScript. Server-only values, a short request form, only the asked-for methods returned, and a 24-hour signed re-reveal.

    3 min read

  85. Full-Stack Development

    Building an iOS Share Extension That Reads a Screenshot and Saves to the App's Database

    How SpenDrop's Share Extension loads an image from any app, stays inside the memory limit, runs Vision OCR and saves to the app's shared SwiftData store.

    5 min read

  86. Full-Stack Development

    Where Does a 4-Second Label Go? Instrumenting a Scan-to-Print Pipeline

    Stage-by-stage tracing of a Web Bluetooth label print, an audit of every sleep in the code, and the rule of not claiming a speed-up until the hardware has measured it.

    6 min read

  87. Developer Journey

    Testing an iOS App With an In-App Test Runner, Launch Flags and XCUITest

    274 logic checks run inside the app from a launch flag, a final check proves no test opened the real database, and six XCUITest flows drive the UI.

    5 min read

  88. Developer Journey

    Implemented, Available, Not Connected: Writing Honest Status Into Project Docs

    "It exists in the repository" and "it runs in production" are different claims. The three-state status model I use across my projects, with real rows from each.

    5 min read

  89. Building Real Systems

    Reference Data Nobody Can Edit: Postgres Triggers, Hash Pinning and Append-Only History

    Protecting the examples an AI system is measured against: a trigger that refuses UPDATE and DELETE, SHA-256 hashes checked by tests, append-only history, and what these do not stop.

    4 min read

  90. Full-Stack Development

    From a Constant Per-Role Cookie to HMAC-Signed, Expiring Sessions

    RPOMS's session cookie was the same bytes for every admin, forever. Replacing it with a signed payload carrying issue time and session id, plus a login throttle that needs no Redis.

    4 min read

  91. Full-Stack Development

    Hardening a Public Photo Upload: Magic Bytes, Header Dimensions and Stripping EXIF Twice

    An anonymous endpoint that decodes images is easy to abuse. How RPOMS AI re-encodes photos in the browser, trusts none of it on the server, and never stores the uploaded bytes.

    4 min read

  92. Full-Stack Development

    Google Sign-In for Shared Workstations: PKCE, Pending Users and Revocable Device Tokens

    Google OIDC with PKCE on a framework-free Node server, users keyed by sub, accounts that start pending, and workstations provisioned with hashed, revocable device tokens that keep working offline.

    6 min read

  93. Developer Journey

    Generating an Xcode Project File From a Script, With Stable IDs

    Both of my iOS apps write project.pbxproj from a script. How the object IDs are made, why hashing names beats a counter, and what it costs.

    3 min read

  94. Full-Stack Development

    Monthly Request Numbers That Never Skip: Counters, Voids and Retries in PostgreSQL

    How RPOMS issues monthly request numbers with no gaps: a locked counter row, number and row in one transaction, voids given back, retries made safe.

    5 min read

  95. Building Real Systems

    Freezing a Label Design in CI by Hashing Its Rendered Raster

    A Vitest test that hashes each label template's JSON and its exact 1-bit print raster, so any change that would move a single printed dot fails the build and the deploy.

    5 min read

  96. AI & Automation

    When a Per-Minute Token Limit Is Smaller Than One Request

    A free-tier limit of 7,000 input tokens per minute, and research papers needing 7,920 to 20,362 tokens per call. Why waiting cannot fix that, and how a working fallback hid it.

    3 min read

  97. AI & Automation

    "Unclear" Is Not One Answer: Five Decision States for an AI Inspection

    An AI check that cannot decide can fail for four very different reasons. How RPOMS AI records which one, maps it to what the public sees, and makes a missing mapping a type error.

    4 min read

  98. Full-Stack Development

    Getting Usable Text Out of Academic PDFs: Signatures, Encryption, Scans and Ligatures

    The PDF ingestion path behind ResearchForge: checking the real file signature, opening print-restricted files, rejecting scans with no text layer, and cleaning text without removing content.

    4 min read

  99. Full-Stack Development

    A Postgres-Backed Express 5 API With No Database Server: PGlite, JWT and Security Tests

    DriveKeep's backend runs PostgreSQL in-process with PGlite, signs HS256 tokens and has 17 security checks. What it does well and what must change first.

    5 min read

  100. AI & Automation

    Exposing a Local Ollama to a Vercel App: A 90-Line Token Gateway and a Cloudflare Quick Tunnel

    Ollama has no authentication, so its port must never face the internet. The small Node gateway RPOMS AI puts in front of it, the tunnel, and how each hop is diagnosed.

    4 min read

  101. AI & Automation

    Evaluating an LLM App When Your Own System Hides the Result

    Evaluating a deployed LLM app with no labelled data, and the three things that produced plausible but wrong measurements: a content-keyed cache, a CDN and a fallback that worked too well.

    5 min read

  102. AI & Automation

    Evaluating a Vision Model When You Only Have Thirteen Examples

    Thirteen labelled photos are not a test set, but they can still be an honest evaluation. Separating what is known from what is assumed, removing leaked annotations, and controls built on purpose.

    5 min read

  103. Full-Stack Development

    Enforcing Architecture Boundaries in a Next.js App With One Test File

    A Vitest file that reads the source tree and fails when a client component imports server code, an admin route skips its auth guard, or a minifier hazard creeps back in.

    4 min read

  104. UI/UX & Product

    Writing a User Guide Into the Spreadsheet Itself

    A stock tracker's in-workbook guide: a colour legend for formula, drop-down and free-text columns, a sheet-by-sheet purpose list, and how the guide drifted from the formulas it described.

    5 min read

  105. Building Real Systems

    Encoding Vague Acceptance Criteria Without Inventing Thresholds

    Criteria that said long, multiple and small with no numbers: how a pure rule engine applies vague words as categories, orders checks for safety and answers UNCLEAR.

    5 min read

  106. Building Real Systems

    Configuration Health You Compute, Not Store: One Model Record Across Three Modules

    How RPOMS merged three definitions of a router model into one record, and flags broken configuration with a pure function instead of an issue table.

    5 min read

  107. Building Real Systems

    Dependent Drop-Downs With INDIRECT and Named Ranges, and What They Cost to Maintain

    A Brand → Model drop-down built with INDIRECT and one named range per brand works well on day one. The two update procedures, orphaned #REF! names and fixed ranges are what it costs later.

    6 min read

  108. Building Real Systems

    Designing a Delivery Module: Scan Boxes, Never Type Serials, Freeze What Left

    How the RPOMS delivery module works: scanned boxes instead of typed serials, a load that must match its quantity, and a snapshot of what actually left.

    5 min read

  109. Building Real Systems

    Proving a Release Deleted Nothing: Row-Count Gates and a Whole-Database Preservation Test

    How RPOMS checks that a release or migration lost no business data: a row-count gate that fails on any decrease, read-only scripts, and a test that compares every row of every table.

    5 min read

  110. Full-Stack Development

    CSV Formula Injection in Exports: The One-Apostrophe Fix

    A name typed as =HYPERLINK(...) runs when someone opens a CSV export in a spreadsheet. The small cell guard RPOMS uses on both client and server exports, and what it leaves alone.

    2 min read

  111. Full-Stack Development

    Letting Another Web App Print Through an Open Tab: BroadcastChannel, Web Locks and COOP

    How a tiny relay page lets another web application print on a Bluetooth printer held by an already-open tab, with one tab answering via a Web Lock and the printer's real result reported back.

    6 min read

  112. Building Real Systems

    When Two Days Fill One Box: Counting Shared Consumables Without Double-Counting

    A packaging box filled across two days must be charged once. How RPOMS derives each day's big-box usage from a running total, and how the rule evolved.

    5 min read

  113. Full-Stack Development

    First-Party Analytics Without Cookies: A Daily-Rotating Salted IP Hash

    Page views and link clicks recorded by the site itself, with no third-party tracker and no cookies. A salted IP hash that changes daily, beacons that survive navigation, and what is still stored.

    4 min read

  114. Developer Journey

    Maintaining a Web System I Didn't Build: Small, Scoped Fixes

    Three small fixes to a Next.js inventory app another developer built: a lazily loaded Excel library, a duplicate fetch on first load, and a reset-password redirect, kept reviewable.

    5 min read

  115. Building Real Systems

    Continuous Label Printing Without Duplicates: Page Counters and "Uncertain" Jobs

    Why one printer job per label made the paper feed and rewind, how multi-page jobs fixed it, and how a print queue decides between a safe retry and a label that may already exist.

    6 min read

  116. Full-Stack Development

    Contact Form Spam Protection Without a CAPTCHA, and Its Honest Limits

    A honeypot, a minimum fill time, a same-site check, strict validation and a database-backed rate limit on a Next.js contact form. What each layer stops, and which ones a script can walk past.

    4 min read

  117. Building Real Systems

    Yesterday Is Not Enough: Choosing Comparison Baselines for an Operations Dashboard

    The five baselines the RPOMS dashboard compares today against, how each is computed, why one rising metric is red, and why missing data shows N/A.

    4 min read

  118. Full-Stack Development

    Chrome Throttled My Bluetooth Printer: Moving Timers Into a Web Worker

    Labels slowed from about 4 seconds to 13 or more whenever the print tab was in the background. The cause was Chrome's timer throttling; the fix was a tiny Web Worker that owns the waits.

    4 min read

  119. AI & Automation

    Choosing an Embedding Model Under pgvector's 2,000-Dimension Index Limit

    A decision record: how ResearchForge picked an embedding model and dimension around pgvector's index limit, cost and reversibility. The choice was made and wired up; no embedding was ever produced.

    3 min read

  120. AI & Automation

    Why Every Real Photo Timed Out: Capping Vision Input at 896 px to Fit a 60-Second Function

    Full-size phone photos never got an answer from RPOMS AI's vision model. Encoding cost grew faster than pixel count; capping at the evaluated scale took 114 s down to 38 s.

    4 min read

  121. Full-Stack Development

    Canonicals That Pointed at a Redirect: www vs Apex, Sitemaps and Permanent Redirects in Next.js

    Every canonical, og:url and sitemap entry on this site named a URL that 308-redirected. The fix, plus the sitemap, feed and redirect decisions made around it in Next.js.

    4 min read

  122. Full-Stack Development

    Calling Supabase's PostgREST Directly From FastAPI: The Details a Mock Won't Tell You

    A Python backend talking to Supabase's PostgREST over plain httpx. Embedded ordering, counts in headers, deletes that return 200, reserved characters, and what mock tests can and cannot prove.

    4 min read

  123. AI & Automation

    Caching LLM Analyses by Content Hash Without Recording Who Uploaded What

    A shared cache for expensive LLM analyses, keyed by a hash of the extracted text. How the key is chosen, what is never cached, and why the cache table has no user column.

    5 min read

  124. UI/UX & Product

    Blank Is Not Zero: Small Input Decisions That Decide Whether a Report Is Right

    Three bugs from RPOMS's daily report: a target of 0 read as unset, a running output collapsed into one number, and one worker split by capitalisation.

    5 min read

  125. AI & Automation

    The 21-Second Benchmark That Was Wrong: Ollama Reuses an Encoded Image

    A vision-model latency figure that was half the real cost, because the benchmark sent the same image twice. How it was caught, corrected, and what a fair benchmark needs.

    3 min read

  126. Building Real Systems

    A Performance Gate That Stopped Crying Wolf: Medians and a Noise Floor

    A baseline-versus-current benchmark flagged regressions on identical code. Medians of three runs and a rule that ignores tiny metrics made it a gate worth trusting.

    4 min read

  127. Full-Stack Development

    Building a Web Screen Around a Barcode Scanner: Enter Keys, Excel Pastes and a Beep That Froze the Page

    How RPOMS's scan screens handle a barcode scanner: Enter-terminated scans, pasted Excel columns, one batched lookup, and a beep that no longer blocks.

    5 min read

  128. Building Real Systems

    An Append-Only Audit Log That Keeps What Was Deleted

    RPOMS's audit log records who acted, from the signed session, and a snapshot of what each destructive action removed, which turns irreversible deletes into recoverable ones.

    4 min read

  129. AI & Automation

    Structured Receipt Extraction With Apple's Foundation Models and @Generable: A Code Walkthrough

    How DriveKeep's iOS code asks Apple's on-device Foundation Models for typed receipt fields and fuses them with Vision OCR. A walkthrough of unverified code.

    5 min read

  130. Full-Stack Development

    An Append-Only Cloud Backup for a Local-First iOS App

    SpenDrop's optional cloud backup never overwrites: per-user Storage folders, no UPDATE policies, a content hash, and a restore that copies local data first.

    5 min read

  131. Full-Stack Development

    The SwiftData Store I Configured Was Never the One Being Used

    Renaming an iOS app opened an empty database. The App Group store URL I had configured had never worked; SwiftData's fallback had been doing the job.

    4 min read

  132. Full-Stack Development

    Keeping Analytics for 90 Days: Roll Up, Then Delete, With pg_cron

    Detailed analytics events kept for a set period, then summarised into daily totals and deleted by a scheduled PostgreSQL function. The retention setting, the job, and the time-zone trade-offs.

    4 min read

  133. Full-Stack Development

    Adding Label Printing to an Existing Next.js App Without Touching the Printer

    The calling side of a print integration: validating SKUs the way the printer app will, passing them in a URL fragment, detecting blocked pop-ups, and refusing to print unsaved changes.

    5 min read

  134. Building Real Systems

    When the Supabase Session Pooler Ran Out: An EMAXCONNSESSION Postmortem

    Admin pages on a Next.js app on Vercel showed a generic error for about six minutes. The cause was Supabase's session-mode pooler hitting its 15-client limit, not the code.

    6 min read

  135. Full-Stack Development

    From Millimetres to Dots: Rasterising a 50×30 mm Label for a 576-Dot Printhead

    How a label template in millimetres becomes a 1-bit raster for a 300 dpi thermal printhead: geometry, thresholding, whole-dot barcodes and why some designs cost more Bluetooth packets.

    6 min read

  136. AI & Automation

    A Photo Quality Gate That Runs Before the Vision Model: Blur, Exposure and Glare From Raw Pixels

    How RPOMS AI rejects blurred, dark, over-exposed and glare-filled photos with plain pixel arithmetic before any model is called, and how the thresholds were calibrated.

    6 min read

  137. Full-Stack Development

    Optimistic Concurrency for a Postgres Upsert, Using the Row's Own updated_at

    Two admins saving the same day meant the second silently replaced the first. One guarded INSERT ... ON CONFLICT statement and a 409 fixed it, and two bugs followed.

    5 min read

  138. Full-Stack Development

    One Person, Referenced Everywhere: A JSON-LD @graph for a Personal Site

    How this site declares its Person and WebSite nodes once and points every article, project page and the homepage at them by @id, and what that forced me to leave out.

    5 min read

  139. Full-Stack Development

    The NIIMBOT B1 Pro Bluetooth Protocol, Packet by Packet

    The frame format, checksum, connect packet, identification reads and the full V4 print sequence I use to drive a NIIMBOT B1 Pro over Web Bluetooth, with what is verified and what is not.

    9 min read

  140. Building Real Systems

    Logging Every Status Change in Excel With VBA to Measure Time per Department

    Formula-driven status changes don't fire Worksheet_Change. How a stock tracker logged them with Worksheet_Calculate, timed each stage, and read the log back with SUMIFS and LOOKUP(2,1/…).

    6 min read

  141. AI & Automation

    Which RM Is the Payment? Classifying Every Amount on a Receipt Screenshot

    A payment screenshot shows fees, balances and advert prices as well as the payment. How SpenDrop labels every RM value, using keywords and screen position.

    6 min read

  142. Building Real Systems

    Generating Barcode and Group SKUs in Excel From Spec Columns

    How an Excel stock tracker built a per-brand serial that rolls past 99, a barcode SKU and a variant group key from spec columns with LET and TEXTJOIN, and where formula IDs break.

    6 min read

  143. Full-Stack Development

    Filling a Word Template in Node.js When Word Splits Your Placeholders

    How RPOMS fills the office's own Delivery Order .docx with JSZip: placeholders split across Word runs, a two-pass replace, and an Excel tracker beside it.

    6 min read

  144. Full-Stack Development

    Running FastAPI and Next.js as Two Services Behind One Vercel Origin

    One Vercel project, a Next.js frontend and a FastAPI backend on the same origin. The routing, the CORS outage it fixed, the image optimizer that vanished, and the Python packaging details.

    5 min read

  145. Building Real Systems

    Stock You Never Store: Deriving Inventory From a Ledger and the Day's Report

    Why RPOMS never stores a stock balance: remaining is worked out at read time from a ledger and the daily report, so edits need no reversal and a figure can be traced.

    5 min read

  146. Malaysia & Cyberjaya

    Building Software in Cyberjaya: The Development Environment Behind the Work

    What a production operations system, a client website, an AI research assistant and a vision inspector actually get built on, from a laptop in Cyberjaya: the machine, the stack, where things are hosted, and the local details that shaped the code.

    6 min read

  147. AI & Automation

    A Vision Model That Only Observes: Building RPOMS AI Without Letting the Model Decide

    A router surface inspector where the vision model reports what it sees and a deterministic rule engine decides. Why the split, what a 7B open model actually scored, the blank-image control that changed the prompt, and a safety gate that turns most answers into "check manually".

    7 min read

  148. Full-Stack Development

    Printing Labels From the Browser Over Web Bluetooth: The RPOMS Print Engine

    A scan-to-label workflow that drives a NIIMBOT B1 Pro directly from Chrome, with no vendor app and no backend. What the protocol work looked like, how 116 tests run without a printer, and what the first real print taught.

    6 min read

  149. Malaysia & Cyberjaya

    The Business Day Is Not the Server Day: Time Zones in a Malaysian Operations System

    A deployed server keeps UTC. A warehouse floor in Malaysia keeps UTC+8. Until eight in the morning, the two disagree about what day it is, which is long enough for a morning delivery to file itself under yesterday.

    4 min read

  150. Building Real Systems

    Staged CSV Import: Validating Operational Data Before It Is Written

    The office already keeps its records in a workbook. Importing that sheet into a production system means matching its headers loosely, reading its dates the way it wrote them, surfacing duplicates before anything is saved, and never letting the client tell the server what a file contains.

    5 min read

  151. Building Real Systems

    One Storage Interface, Three Backends: How RPOMS Picks Its Database

    PostgreSQL on Vercel, MySQL on cPanel, or a folder of JSON files on a laptop, chosen by which environment variables exist. What that bought, what it cost, and the production lessons about pooled connections and reads that never came back.

    6 min read

  152. Full-Stack Development

    Gating a CV Download Behind a Server-Signed Grant in Next.js

    A public portfolio, a CV with a phone number in it, and a public repository. How this site releases three contact fields and one PDF only after a form, without a database and without trusting the browser.

    4 min read

  153. Full-Stack Development

    A Live GitHub Contribution Heatmap in Next.js, Without a Token in the Browser

    How this site's homepage renders real GitHub contribution data: a server-fetched calendar cached for an hour, a documented API with an undocumented fallback, and one small client island for the tooltip.

    5 min read

  154. Full-Stack Development

    Every Policy Was Correct, and Every Policy Was Inert

    A data-isolation defect that passed the entire test suite, shipped, and behaved perfectly. What it took to find it, and why the fix was to stop asking the application to be careful.

    4 min read

  155. AI & Automation

    When Not to Fall Back to Another AI Provider

    Automatic failover between model vendors is easy to build and easy to build wrong. Most errors should never trigger it.

    3 min read

  156. AI & Automation

    Making an LLM Admit the Paper Doesn't Say That

    The dangerous failure of an AI summarising tool is not a blank answer. It is a plausible one about a section that was never in the source. Enforcing groundedness in four layers instead of asking for it once.

    4 min read

  157. Full-Stack Development

    Cutting a Page's Image Payload From 12 MB to Under 3 MB

    The performance and accessibility pass on a production homepage: what was actually slow, what fixed it, and why most of it was not clever.

    4 min read

  158. Full-Stack Development

    Verifying a Static Site You Built by Hand

    Hand-written HTML has no type checker and no test runner. On a production build I wrote the guarantees instead, as a post-build script that fails the build.

    4 min read

  159. Full-Stack Development

    Rebuilding a Design-Tool Prototype as a Production Website

    An approved design arrived as a self-extracting bundle running React from a CDN. Shipping it meant removing almost everything and keeping the part that was actually the specification.

    5 min read

  160. Building Real Systems

    Reporting From Operational Data

    What makes operational reporting actually useful for decisions, instead of just being a record of what happened.

    1 min read

  161. UI/UX & Product

    Why Internal Software Needs Good UX

    Internal tools get less design attention than public products, even though the people using them have no choice but to use them.

    1 min read

  162. AI & Automation

    Replacing Repetitive Manual Work With Software

    How to tell whether a repetitive manual task is actually worth automating, and what to check before building anything.

    1 min read

  163. Developer Journey

    What an IT Systems Role Actually Involves

    A grounded look at what IT systems work covers day to day, beyond the narrow idea of fixing computers.

    1 min read

  164. UI/UX & Product

    Designing for Desktop and Mobile Before Development

    Planning responsive behavior as part of the design phase, instead of leaving it as a problem for development to solve alone.

    1 min read

  165. UI/UX & Product

    Translating Figma Components Into Reusable Code

    How design components in Figma map to reusable UI components in code, and where that mapping gets harder than it looks.

    1 min read

  166. UI/UX & Product

    From Figma Design to Production Website

    What actually happens between a finished Figma design and a working, deployed website.

    1 min read

  167. UI/UX & Product

    Designing a Website in Figma Before Development

    Why doing the design work in Figma first, rather than designing in the browser, changes how the build goes.

    1 min read

  168. Full-Stack Development

    Why System Maintenance Matters After Deployment

    Shipping an operational system is the start of the work, not the end. What ongoing maintenance actually involves.

    1 min read

  169. Building Real Systems

    Why Software Developers Should Understand the Physical Process

    Building software for a real operation goes better when the developer understands the physical process it supports, not just the data model.

    1 min read

  170. Building Real Systems

    From Manual Workflow to Digital Workflow

    What actually changes when a manual, paper-or-spreadsheet process becomes software, and what shouldn't change.

    2 min read

  171. Building Real Systems

    How Admin Panels Help Manage Operational Data

    What a well-designed admin panel actually needs to do for a production or operations system, beyond CRUD screens.

    1 min read

  172. Building Real Systems

    Common Problems in Manual Production Tracking With Spreadsheets

    The specific ways spreadsheet-based production tracking breaks down in practice, the tell that says it is time to move, and what a replacement has to remove.

    3 min read

  173. Building Real Systems

    What Is a Production Management System?

    A plain explanation of what production management software actually does, and why it's a different problem from a generic business app.

    1 min read

Also available as an RSS feed.