RPOMS
Router Production Operations Management System
IT Systems Architecture, Full-Stack Engineering, Production Line Operations & Deployment
Operational Workflow & State Machine
End-to-End Pipeline- 01Stock booked in and scanned into registry
- 02Refining and cleaning with real-time audio cues
- 03Packed into numbered boxes with thermal label printing
- 04Control Center ledger recording via atomic folded CTEs
- 05Delivery dispatch with QR-coded Delivery Order
- 06Customer portal verification & mobile ePOD signature capture
RPOMS ecosystem
Separate systems- Related system, same programmeRPOMS AI
A router surface inspector: photo quality gate, a vision model that only observes, and a deterministic rule engine that decides. Own repository and database; never connects to RPOMS. Deployed, with no model active in production yet.
Read its case study - Subsystem, linked from the Printing pageRPOMS Print Engine
Scan-to-label printing to a NIIMBOT B1 Pro thermal printer straight from the browser over Web Bluetooth. Deployed standalone; RPOMS's Printing page sends each saved scan to the running engine tab as a label request.
Read its case study - Related system, same programmeTelco Device Operations & Quality System
Floor operations app for the router retest and cleaning facility: supervisor distribution, cleaner productivity points by difficulty level, and daily target tracking. Own database; never connects to RPOMS.
Read its case study
Overview
RPOMS is the operations platform for a router-refurbishment programme that Established Malaysian technology company runs with Malaysia's No. 1 E-Waste Recycling Company and Leading Malaysian telecommunications provider. It records each day's production, tracks every router by serial number from acceptance into a numbered box and out on a delivery, keeps the stock of routers, chargers, cables and boxes, and produces the delivery paperwork the office already uses. A customer-facing portal enables electronic proof of delivery with digital signatures, while a second, locked-down build of the same code gives the Ecommerce team a portal for requesting stock.
The comparison to a warehouse or resource-planning system is about shape rather than scale. It is not a commercial ERP suite and does not try to be one: there is no finance, procurement or HR module. What it shares with that category is the structure, a single operational data model that inventory, production, delivery, workforce, Control Center and reporting all read from, so a figure on a dashboard traces back to the event that produced it.
It is one Next.js 15 application: over 65,000 lines of TypeScript across 96 compiled routes and 2,388 automated tests. Every screenshot on this page was taken from that application running locally on synthetic data.
Problem
A physical production line (intake, acceptance, cleaning, packing, delivery) was being coordinated through spreadsheets shared across a team. That made it hard to know, at any moment, what had actually happened on the floor: what stock remained, who did what, which box a serial went into, whether a delivery matched what was scanned, or whether a report was still current.
Spreadsheets do not validate. They have no single source of truth once someone keeps a private copy to be safe, and no audit trail once a number looks wrong. The spreadsheet is still visible in the code: the model-detection rules were seeded from the team's Excel formula, and a registry row is described as the web equivalent of a row in the Excel ACCEPTED list.
Context
The programme refurbishes used routers in batches, each with a target. That is a different problem from manufacturing: units arrive in unknown condition and unpredictable quantities, and each one carries a serial number the system does not get to choose.
The operation runs on a physical floor in Malaysia, with a small team, a shared set of consumables, two warehouse sites, and delivery paperwork a customer already expects in a particular format. Those constraints shaped the software more than any specification did.
Approach
The first rule was that the software should fail in the safe direction. A missing password disables that login rather than falling back to a known value. A missing session secret stops the application in production. A missing deployment flag leaves production write-locked rather than silently live. A preview deployment pointed at the production database refuses to start serving.
The second rule was that a number should be traceable. Stock is derived from the full history of adjustments and consumption rather than stored as a running total, so a figure that looks wrong can be walked back to the day that produced it.
The third rule was that business rules belong in one place. The arithmetic that decides how many packaging boxes a day's output consumes lives in a single module that the report form, the inventory and the Ecommerce planner all call, so they cannot disagree about the same day.
My Role
I am the only developer on RPOMS. Of 292 commits on the production branch, every one except an uploaded copyright file is mine: the data model, every module, authentication and access control, the storage layer, the tests and CI, the remediation of two code audits, the deployment and staging runbooks, and the production releases.
I work as IT Systems & Operations Lead around RPOMS, so I also work directly with the side it supports: the production line, the stock it consumes, and the people running it day to day. RPOMS models a physical process closely enough to run it, which only works if the person building it understands the process and not just the schema behind it.
How the work flows
Two things are tracked in parallel. The Daily Production Report records how many routers each person accepted, cleaned and packaged that day, and stock is deducted from those figures. Separately, the Registry, Pack and Delivery screens follow individual routers by serial number into boxes and onto deliveries.
Cleaning is recorded only as a daily count per person. There is no per-serial cleaning state, and the system does not pretend there is. Alongside the main line, the Ecommerce team requests stock, an admin approves it, stages the exact routers, and transfers them, and only that transfer deducts anything.
Daily Production Report
The day's figures are entered once. Saving updates the dashboard and deducts stock in the same step: routers by accepted plus retired, chargers and cables by packaging. Batch and target carry over from the previous report, and Completed is the batch so far plus today's packaging, so progress is continuous rather than restarting each day.
For a plain admin, the server does not trust the totals it is sent. It recomputes Accepted, Cleaned, Packaged and Completed from the workforce rows, freezes batch and target, and only lets an existing output grow. Two admins saving the same day no longer overwrite each other: each save carries the row's revision, and a stale one is refused with a message to reload.
Serial Registry and Packing
Every router is recorded by serial number, model, who accepted it and when. The model is detected from rules stored as data (a prefix and an optional length, longest prefix first), so a new model needs a rule rather than a release. A serial no rule recognises is kept, flagged and shown at the top of the list.
Packing scans serials into a numbered box. A serial that is unknown, not accepted or already in another box is flagged, and the box will not close around it unless the close is forced deliberately. A box closed short of its capacity says so on the list, and each box prints a label with a QR code of its number.
Delivery and paperwork
A delivery is built by scanning box numbers. The serials inside come from the registry and are never typed. The delivery cannot be saved until the scanned load matches the quantity it was raised for; the server enforces the same rule, and only a Super Admin can accept a short load. Saving writes the delivery, its boxes and each router's delivered state in one transaction.
The Delivery Order is generated from the office's own Word document with the details filled in, not redrawn. Word splits a line of text across several runs, so a placeholder can be broken in one place and intact in another; the generator does two passes for exactly that reason. The tracker exports to Excel in the column layout the customer's sheet expects.
Inventory and workforce
Stock is never stored as a balance. Remaining is always what was booked in minus what was consumed, worked out when it is read, per item and per model, so editing or deleting a report cannot leave a stale figure behind. Every movement, including those written by an Ecommerce transfer, appears in one ledger.
Workforce output is measured against per-person targets that can be set by department, by day, or for one person on one day. Names are matched case-insensitively, and the spelling shown is the one a worker is recorded under most often.
Router-model configuration
A router model used to be described in several places: a stock variant in inventory, detection rules in the registry, a request code in Ecommerce. They could drift apart, and a second spelling of the same model quietly became a second model. The model is now one record that all three modules read. A new name is matched against the existing models first, so a variant spelling links to the model that already exists instead of duplicating it, and detection rules point at the model by ID rather than by name.
Configuration health is computed on every request and never stored: a model with no serial prefix or length, an orphaned or conflicting rule, or a request code that is missing, invalid or not yet confirmed is flagged on the Super Admin tabs, on a strip in each affected module and in a Needs attention list with the fix beside it. Request codes print only after a Super Admin confirms them, a model that still has rules cannot be deleted from under them, and every configuration write is Super Admin only. The schema change is additive, and a test builds a production-shaped database to prove the migration changes no existing value.
Ecommerce stock requests
The Ecommerce team asks for routers or sealed boxes through a portal that shows them their own requests and nothing else: no stock levels, no admin screens. Each request gets a number of the form ECR/YYMM/R/CODE/NN from a per-month counter, and a network retry returns the request the first attempt created instead of raising a second one.
An admin approves or rejects it, stages the exact routers by serial or by box (each one checked against the registry), and transfers them from loose stock or a storeroom. The client never sends a charger or box quantity; the server derives them. The same deduction plan drives both the preview and the commit, and a void reverses a transfer.
Dashboard and reporting
The dashboard answers how today went: the four figures against yesterday, batch progress, today's workforce against target, a trend, and a comparison against yesterday, a seven-day average, last week, this month or a custom range, because a comparison supports a decision and a raw count does not. It refreshes itself, and switches to Arabic with the whole layout mirrored right to left.
Report history is searchable by date and batch and exports to PDF.
Architecture
One Next.js application with no separate backend service. Pages are server components that read the store directly; writes go through route handlers that check the role and validate every body with Zod. A single middleware sits in front of every request: it refuses a preview or laptop pointed at the production database, applies the production write lock, scopes the Ecommerce build, and sets security headers. Authentication is deliberately decided in each page and route, not there.
One storage interface, three backends, selected by which environment variables are present: PostgreSQL on Supabase in production, MySQL for an earlier cPanel path (report store only), and atomic JSON files for local work. Postgres tables are created on demand behind per-store schema stamps, and only one cold-starting instance wins the build, which matters when several deployments share a database. Every read runs under a deadline, and where a fallback would be dishonest the caller gets a distinct 'could not read' value instead of an empty result.
Technical Decisions
Four roles (viewer, Ecommerce, admin, super admin), each with its own credentials. A role whose password is not configured is switched off entirely. Sessions are an HMAC-SHA256-signed cookie carrying the role, when it was issued and a session id, compared with a timing-safe function, httpOnly, sameSite and secure in production. A viewer's session lapses after twenty-four hours; staff sessions last seven days. Sign-in attempts are throttled per address.
Big packaging boxes are not calculated with a ceiling function. One box per ten packaged units, plus one more once the remainder reaches seven, because a box near enough to full has already been opened and sent, while a smaller remainder will be finished by the next day's work and would otherwise be counted twice.
The business day is resolved in Asia/Kuala_Lumpur rather than from the server clock. A deployed server keeps UTC, which would not turn the day over until eight in the morning locally, long enough for early packing to file itself under the previous day.
Translations are typed against English as the source, so a string added in English fails the build until every other dictionary supplies it.
Engineering challenges
Most of these came out of two read-only audits of the codebase, the first of which recorded 44 findings, six of them rated P0.
Silent overwrites: two admins saving the same day meant the second replaced the first with no trace. Each save now carries the row's revision, and a stale save is refused with a 409.
A client-sent 'this came from a CSV' flag relaxed the add-only rules. The server now re-parses the attached worksheet and decides for itself which sections it supplied, and refuses a worksheet dated for a different day.
Every preview deployment was configured with the production database. A guard now makes a preview refuse the production database with a 503, work flows through a staging branch, and a one-way refresh script copies production to staging with names anonymised.
Deployments sharing one database raced to build schema on cold start, holding an exclusive lock. The build is now claimed with a single statement and a sentinel, and new columns sit behind their own marker keys so two versions of the code cannot keep undoing each other.
Box stock started mid-operation, with thousands of routers already packed. Counting them would have produced a deficit no correct booking-in could explain, so box stock starts from an opening figure on a fixed date and only later packing is counted.
A production incident, written up as one: for about six minutes the admin panel showed an error page. The cause was not the code but connection-pool exhaustion, because production and a preview shared Supabase's session-mode pooler, which allows fifteen connections. Production now connects through the transaction pooler, which its public health endpoint reports, and the code detects which pooler a deployment is on from the host and port alone, warns when production is on the wrong one, and fails the environment check for it.
Testing and verification
2,388 automated tests across 198 test files, written with Vitest. The database files run real SQL against PGlite, PostgreSQL compiled to WebAssembly and served in-process, so transactions, locking, concurrency and schema setup are tested with the production driver and no database server. CI runs typecheck, lint, the tests, a production build and a dependency audit on every push.
The test suite expanded across release milestones: 958 tests in the 28 September baseline, 1,637 tests in the 20 October release, 2,317 tests in the 4 November Delivery Tracking & ePOD production release, and 2,388 tests in the 6 November Control Center staging branch. Real PostgreSQL 17 concurrency tests validate adversarial scanner storms, ensuring zero duplicate writes and complete rollback integrity under simulated deadlocks.
There is no browser end-to-end suite yet; a Playwright smoke test per role is on the backlog.
Deployment and environments
The project deploys to Vercel from Git: pushing the main branch deploys production, and every other branch builds a preview. Production data lives in Supabase PostgreSQL. Work flows through feature branches and a staging branch before it reaches main, and a data-preservation check compares every table's row count before and after a release. The September release went out as one verified branch: main was fast-forwarded to it, following a written release plan that lists the additive schema steps a first cold start runs, the release order and the rollback.
Since October 2026 staging runs on its own database, reported on its health endpoint, and the application refuses to start a preview against the production project. In November 2026, an end-to-end backup restoration drill proved full database restoration on an isolated PostgreSQL copy using the pg_trgm extension, verifying zero data loss.
Current result
In production, the dashboard and the Daily Production Report are live: the day's figures are entered for real, stock is deducted for real, and the dashboard reads back what was saved. The Ecommerce portal runs as its own build of the same code.
The registry, packing, delivery and paperwork, workforce and inventory modules are complete, but they sit behind a deployment-level write lock while the programme works through sign-off: while the lock is on, those screens show an under-development notice in production rather than their data. The lock is enforced at one middleware chokepoint, is on by default in production, and names the modules allowed to write, so a module goes live by being named rather than by accident.
On 28 September 2026 the staging line was released to production: the remediation of both audits, the audit log, the environment guard, the login throttle, the test suite and CI, the full Ecommerce module, the centralised model configuration and the connection-pooler diagnostics. Production deploys from main on Vercel, and that release is what it runs today.
October 2026: Refining, Printing and the central platform
The 12 October production release added multi-box delivery batching and paginated inventory history. An 8,332-row historical router archive now lives in the production database as its own table with an import ledger; the 250,000-router import it was designed for was measured head-to-head on an isolated copy and has not been run against production.
Built between 13 and 20 October and released on 20 October: a Refining workstation where the first scan starts a cleaner's session and each scan registers the router once, with a partial unique index rather than a per-scan lock catching concurrent duplicates; a Printing page that saves scans side by side and sends each label to the running Print Engine tab as soon as its own save answers, where a lost answer is shown as status unknown and never as not saved; Today's Refiner Breakdown, drill-down and Bring from Refining into the Daily Report; a Router History page with one toolbar and a Filters panel instead of a filter grid; and Row Level Security on the Refining tables.
The central platform work adds Google sign-in through the Supabase project's provider with server-side PKCE and no client library, a services portal, and per-service grants: a Printing-only account sees no other tab, access requests name capabilities, and a revoked grant takes effect on the next request. Registry hardening sorts the first page on an indexed column, from 160 to 200 ms down to under 1 ms at 250,000 routers on an isolated copy, and the application now refuses to build or alter a store's schema on the production database. The 20 October handover package lists the five schema-only migrations production needs, in order, each with a rollback block; 1,637 tests pass on that branch.
Every item in the second and third paragraphs was exercised on the staging deployment, on its own database, before release; the production schema changes run as the five approved, schema-only migration files, before the build serves traffic.
November 2026: Delivery Tracking, Electronic Proof of Delivery (ePOD) & Production Release
Released to production on 4 November 2026 under explicit owner instruction (RPOMS_DELIVERY_TRACKING=1, RPOMS_EVIDENCE_STORAGE=vercel-blob): a full delivery tracking subsystem and electronic proof of delivery (ePOD) with zero regression on existing delivery orders. Every delivery order now carries a permanent, PIN-protected QR code that links to a dedicated customer-facing tracking portal (/cp/do/[id]). The system generates Word Delivery Orders matching the office's template byte-for-byte with embedded QR verification, eliminating manual paperwork discrepancies.
The ePOD mobile interface enables receiving customers and logistics operators to capture digital signatures directly on touchscreen devices. Proof uploads are validated via file magic bytes (strictly JPEG, PNG, or WebP under 4 MB) and hashed with SHA-256 before being committed to an isolated private blob store (rpoms-epod-production-proofs). A five-stage state machine (staged, in_transit, out_for_delivery, delivered, and delivery_discrepancy) governs order lifecycle transitions, supported by automated discrepancy reporting when delivered unit counts diverge from the scanned load.
Extensive layout verification ensured 32 of 32 responsive viewport checks passed cleanly from 320 px to 1280 px across dark and light themes, while production performance baselines showed scan-to-screen response times dropping from 316 ms to 81 ms on packing and 75 ms to 39 ms on registry scans.
Real-Time Control Center & Immutable Production Ledger
Staged on 5–6 November 2026 (feat/control-center-2026-11-05), the RPOMS Control Center introduces real-time operational monitoring alongside an append-only production ledger (rpoms_production_ledger). To eliminate the risk of database locks and round-trip overhead on the warehouse line, ledger history is recorded using folded common table expressions (CTEs) within the router-move statement itself over RETURNING. This architecture guarantees zero standalone ledger round trips and zero duplicate entries on retries or concurrent scanner storms.
Data integrity is enforced at the PostgreSQL engine level: database triggers explicitly refuse UPDATE, DELETE, and TRUNCATE statements across all three Control Center tables (rpoms_production_ledger, rpoms_asset_specifications, and rpoms_progress_adjustments) for every database role, including the application itself. Row-level security revokes all public and anonymous privileges, preventing unauthorized PostgREST exposure.
An Asset Specification Matrix tracks model component requirements with versioned immutability, while supervisor adjustments record before-and-after deltas in an audited ledger without altering historical scan records. Keyset pagination over idx_cc_ledger_created guarantees consistent sub-millisecond retrieval across millions of historical events.
Audio Feedback Engine & Warehouse Ergonomics
High-throughput warehouse operations suffer when technicians must continuously glance up from physical barcode scanners to computer screens to confirm each read. To solve this ergonomic bottleneck, an audio feedback engine was integrated across six core operational scanning modules: Intake, Acceptance, Refining, Packing, Delivery Loading, and Dispatch.
The engine plays immediate, distinct auditory cues: a clean chime for accepted units and a crisp warning buzzer for rejected, unassigned, or duplicate serials. Sound synthesis runs entirely client-side with zero network latency, ensuring audio playback never stutters or blocks the UI thread during rapid barcode scanning runs.
Hardware Lifecycle & Multi-Cycle Rework Architecture
Refurbishment facilities frequently encounter routers that fail secondary functional testing or require component rework (such as port resoldering or cosmetic casing swaps) after initial acceptance. The RPOMS Rework architecture (RPOMS_REWORK=1) models this cyclical reality without corrupting the historical audit trail.
Routers routed into rework preserve their initial intake serial number, original batch origin, and historical test notes while initiating a secondary processing lifecycle. When reworked units re-enter the packaging line, the system enforces secondary quality-check clearances, prevents duplicate box assignments, and preserves both first-box and final-box lineage for post-delivery warranty investigations.
High-Scale Registry & Backup Restoration Verification
The router registry is benchmarked for large enterprise scale: 250,000+ historical router records are indexed using PostgreSQL pg_trgm trigram indexes, enabling sub-millisecond fuzzy prefix and serial searches even under heavy warehouse load.
Disaster recovery readiness was verified through an end-to-end production dump and restore drill (1,269,977 bytes dump, SHA-256 verified). The restoration verified table schemas, row-level security policies, and trigram extensions, proving zero operational data loss and rapid recovery capability.
What's live, and what isn't
“It exists in the repository” and “it runs in production” are different claims. This is the difference, stated rather than left to be assumed.
- ImplementedDelivery Tracking & Electronic Proof of Delivery (ePOD)Live in production since 4 November 2026 (RPOMS_DELIVERY_TRACKING=1). Customer portal (/cp/do/[id]), mobile digital signatures, Word DO with QR code, and private blob evidence storage.
- Built, not liveReal-Time Control Center & Production LedgerStaged on feat/control-center-2026-11-05. Append-only ledger using folded CTEs inside router moves, triggers refusing mutations, and 2,388 passing tests.
- ImplementedAudio Feedback Scanning EngineLive in production across six scanning modules, providing instant auditory confirmation for rapid barcode scanning.
- ImplementedDashboard (English / Arabic)Live in production. Reading is never blocked, so every figure and chart renders from real data.
- ImplementedDaily Production ReportLive in production. Writes report data and deducts stock in the same step.
- ImplementedEcommerce request portalRuns as a separate, locked-down build of the same code. The full Ecommerce module, including registering unknown routers on transfer and stored model codes, is in the production release of 28 September 2026.
- Built, not liveCentralised router-model configurationIn the production release of 28 September 2026: one model record shared by inventory, the registry and Ecommerce, Super Admin-confirmed request codes, and derived configuration-health checks. Its writes sit behind the same deployment-level write lock as the registry.
- Built, not liveSerial registry, packing, delivery and paperwork, workforce, inventoryComplete, held behind a deployment-level write lock pending programme sign-off; while it is on, these screens show an under-development notice in production.
- ImplementedTransaction pooler and connection diagnosticsProduction connects to Supabase through the transaction pooler, confirmed by the live health endpoint, after a session-pooler exhaustion incident on 26 September 2026.
- ImplementedAudit remediation, audit log, environment guard, login throttleReleased to production on 28 September 2026, with CI passing on main and a successful Vercel production deployment.
- ImplementedSeparate staging database and verified backup restorationStaging runs as a Vercel preview on its own database. Production backup dump (1.27 MB) and restore proven with byte-identical schema and pg_trgm extension verification.
- ImplementedRefining and Printing workstationIn the 20 October 2026 release: scan sessions per cleaner, duplicate protection, Today's Refiner Breakdown, Bring from Refining, Router History filters and CSV export. Its four schema-only migrations run before the build serves traffic.
- ImplementedGoogle sign-in, services portal and per-service accessIn the 20 October 2026 release: Google proves identity, a Super Admin grants access per service and capability, and revocation takes effect on the next request. Optional in production; password logins keep working without its migration.
- ImplementedRPOMS Print Engine integrationThe Printing page links one named Print Engine tab and sends each saved scan as a label request; the engine side is live at print.rukon.dev since 19 October 2026 and the RPOMS side since the 20 October release. A full-batch run on the line is the next validation step.
Technical stack
Application
Data & persistence
Interface & reporting
Documents & import/export
Quality & platform
Limitations
- Accounts are shared per role, so the audit trail records a role and a session, not a named person.
- The login throttle is per server instance, and sessions cannot be revoked individually; both need shared tables that are designed but not written.
- Some programme-wide baselines are still constants in code rather than settings.
- Employees and workforce rows are matched by name rather than linked by ID.
- Only the dashboard is translated; the admin panel is English-only.
- The content security policy still allows inline scripts, and the daily report form is one very large component.
- Navigation still differs by role, which reveals that a higher role exists. Blocked actions themselves never name it.
What's next
- 01Tokyo request-level A/B performance verification on staging Control Center.
- 02Legal review of customer-facing ePOD wording before universal rollout.
- 03Shared login throttle and server-side session revocation, then per-user accounts.
- 04Foreign key from routers to boxes and a join table for Delivery Orders.
- 05A Playwright smoke test for each role.
- 06Verify the Printing to Print Engine link on the line with the B1 Pro.
Source and further reading
RPOMS is proprietary software built for a live operation. The screenshots on this page were captured from the real application running locally on synthetic demo data: every name, serial, customer and figure in them is fictional, and the dashboard's programme-wide totals are left out. No production data, customer details or credentials appear.
Finished the technical breakdown?
Return to the concise HR overview or discover other projects in the portfolio.
Writing from this work
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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".
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.
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.
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.
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.
Reporting From Operational Data
What makes operational reporting actually useful for decisions, instead of just being a record of what happened.
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.
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.
Why System Maintenance Matters After Deployment
Shipping an operational system is the start of the work, not the end. What ongoing maintenance actually involves.
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.
From Manual Workflow to Digital Workflow
What actually changes when a manual, paper-or-spreadsheet process becomes software, and what shouldn't change.
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.
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.
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.


















