Rukon
Topic

Full-Stack Development

Next.js, TypeScript, Python, PostgreSQL and the deployment path: how the pieces are wired, what broke in production, and what the fix taught.

Most of this comes out of RPOMS.

  1. 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

  2. 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

  3. 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

  4. 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

  5. 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

  6. 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

  7. 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

  8. 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

  9. 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

  10. 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

  11. 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

  12. 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

  13. 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

  14. 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

  15. 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

  16. 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

  17. 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

  18. 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

  19. 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

  20. 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

  21. 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

  22. 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

  23. 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

  24. 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

  25. 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

  26. 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

  27. 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

  28. 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

  29. 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

  30. 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

  31. 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

  32. 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

  33. 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

  34. 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

  35. 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

  36. 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

  37. 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

  38. 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

  39. 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

  40. 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

  41. 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

  42. 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

  43. 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

  44. 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

  45. 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

  46. 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

  47. 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

  48. 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

  49. 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

  50. 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

  51. 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

  52. 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

  53. 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

  54. 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

  55. 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

  56. 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

  57. 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.

    5 min read

  58. 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

  59. 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

  60. 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

  61. 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

  62. 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

  63. 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

  64. 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

  65. 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

  66. 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

  67. 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

  68. 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

  69. 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

  70. 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

  71. 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

  72. 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

  73. 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

  74. 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

  75. 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

  76. 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

  77. 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