Skip to content
Dotarus

Ship Logger

Ship Logger is a warehouse scan station for OTC Shoppe Express's outbound shipments across three carriers — ePost Global, UPS, and DHL. Packers scan tracking numbers off a shared PIN login; the app detects the carrier, groups ePost Global parcels into consolidated boxes, blocks a number already shipped in a prior submitted shipment, and resolves any tracking number straight back to its Shopify order. A carrier invoice audit catches billing overcharges an undocumented ePost Global feed and ShipStation's own quotes can be reconciled against, and a daily exceptions sweep surfaces stuck or stale shipments before a customer has to ask.

9 min read
Ship Logger: a warehouse scan station for outbound shipments across ePost Global, UPS, and DHL

Introduction

Ship Logger is a warehouse scan station built for OTC Shoppe Express's outbound shipping desk, covering three carriers: ePost Global (EPG), UPS, and DHL. A packer signs in with a shared 4-digit PIN, scans tracking numbers as parcels go out the door, and the app auto-detects which carrier each number belongs to, groups ePost Global parcels into the numbered boxes they physically ship in, and blocks a number that's already recorded as shipped in an earlier submitted shipment. It's a standalone Next.js app on Vercel, with a Shopify custom app wired in purely as a server-side API credential — packers never need a Shopify login.

Ship Logger scan screen showing per-carrier totals, box chips, and a live manifest of scanned tracking numbers

Background

Before Ship Logger, the warehouse's entire shipping record was whatever Shopify and the carriers themselves happened to retain. There was no record of what went out on a given day, in which physical box, under which master airbill — so when a customer or a carrier disputed a shipment weeks later, the only way to research it was to dig through Shopify one order at a time, with no way to go the other direction and turn a tracking number back into an order. ePost Global's consolidation workflow made this worse: many parcels get packed into shared 20×20×20 master boxes that ship under one airbill, and nothing recorded which parcel went into which box. Three carriers also meant three different workflows — EPG consolidated and boxed, UPS and DHL each one parcel, one label, shipped direct — that a packer had previously had to track in their head.

The brief was to build a scan station that takes zero setup for the packer (land on the page, start scanning), make every day's shipment a searchable record afterward, and connect a scanned tracking number back to the Shopify order behind it without ever putting warehouse staff into the Shopify admin.

What it does

A packer's day starts at a numeric PIN pad — no username, no password, just a 4-digit code that identifies them and opens (or resumes) that day's shipping session. From there:

  • Scanning: a single input field listens for a hardware barcode scanner acting as a keyboard wedge. Each scan is checked against UPS/DHL check-digit validation, classified by carrier from its prefix and shape, and either added to the manifest or flagged as a misread. ePost Global scans land in whichever box is currently active; UPS and DHL scans bypass boxes entirely and go straight onto the session list — same field, no mode switching.
  • Submit: closing out the day requires the shipment-level AWB and master UPS tracking number for any EPG boxes, which Ship Logger can draft and buy directly through ShipStation rather than making the packer go generate it elsewhere.
  • History and search: every submitted day is a searchable record at /shipments — paste in a tracking number, an order number, or a recipient name and land on the exact shipment, box, and packer, no matter how long ago it shipped.
  • Carrier status: nightly crons refresh EPG, UPS, and DHL tracking status for every scan not yet in a terminal state, so a shipment's detail page shows live carrier status next to each tracking number without anyone leaving the app.
Ship Logger Shipments Log showing a 30-day volume chart by carrier and a searchable history of submitted shipments

The problems it was built to solve

Each of these came from a real gap in how the warehouse ran before Ship Logger, starting with the smaller day-to-day friction and ending with the one that costs real money every month.

A misread scan quietly becoming a bad record

A warehouse barcode scanner is just a very fast keyboard, and a bad read — a dropped character, a double-fire — looks identical to a real one unless something checks it. Left unchecked, that produces a phantom tracking number sitting in the day's manifest with nothing to show it's wrong until someone goes looking for it later.

The fix: every UPS and DHL scan runs through check-digit validation before it's accepted, with a distinct amber warning ("Looks like a misread — rescan?") rather than a silent accept. Duplicate handling is split deliberately: re-scanning a parcel already in today's session is disregarded with a quiet toast naming the box it's already in, while re-scanning a number from a previously submitted shipment blocks loudly, naming the date, box, and packer who shipped it — that one takes an explicit admin override, because it means a parcel is recorded as going out on a day it didn't.

No way to trace a tracking number back to its shipment, weeks later

Before Ship Logger, "what day did this ship, and in which box" had no answer except memory or digging through loose paperwork. A carrier dispute or a customer question arriving a month after the fact meant starting from nothing.

The fix: every submitted day becomes a permanent, searchable record. Global search on /shipments takes a tracking number, order number, or recipient name and resolves straight to the shipment, the specific box, the ship date, and who packed it — the feature that directly replaces "digging through Shopify."

Carrier status scattered across three different places

Each carrier reports shipment status its own way, through its own site, in its own format — UPS's Track API returns HTTP 200 even for a tracking number it has no record of (a quirk the app has to detect by reading a warning code rather than a status code), and ePost Global has no official self-serve API at all. Checking on an in-transit parcel meant bouncing between three different sites by hand.

The fix: a nightly cron refreshes status for every scan not yet in a terminal state, across all three carriers, and surfaces it directly on the shipment detail page next to each tracking number. ePost Global's status comes from an undocumented, unofficial endpoint that returns structured JSON with no authentication — verified working but with zero SLA, so the integration treats a failure there as an expected, non-fatal event: log it, show a small "status unavailable" banner, keep the carrier link-out working, and keep the rest of the app running regardless. That resilience posture matters because it's the one carrier connection in this app that could disappear without notice at any time.

Shopify's Admin API has no supported way to search orders by tracking number — a long-standing, repeatedly-confirmed gap in its own API surface. Without that link, a packer looking at a tracking number on the bench had no fast way to know whose order it was or where it was headed, and a question like "did this one actually go out" meant a separate trip into the Shopify admin.

The fix: for ePost Global, the app resolves orders through ERef — EPG's own external-reference field, which turns out to be populated with the Shopify order name at label time, giving a fully supported lookup path (orders(query: "name:...")) with no webhook infrastructure needed. UPS and DHL parcels, which carry no such reference, resolve through a locally-maintained order index built from Shopify's fulfillment webhooks. Either way, the order's name, destination, and shipping charge appear right next to the scan the moment it's recorded — enrichment with no per-scan network round-trip, and a parcel that resolves to no order at all is surfaced as a warning rather than silently dropped.

Carrier invoices quietly overcharging, with nothing checking them

EPG bills per parcel against whatever ShipStation quoted when the label was bought, and invoices arrive as a spreadsheet with no built-in way to tell whether a given line was billed correctly. A parcel billed twice, billed at a higher weight than it actually was, or simply charged above the quoted rate looked exactly like a correct line unless someone cross-checked every row by hand — and across a few hundred parcels a month, that's real, recurring money leaking out unnoticed.

The fix: the Invoice Audits page matches every invoice line to its scan (falling back to the final-mile tracking number when needed), compares the billed amount to ShipStation's quote, and sorts each parcel into overcharged, undercharged, billed twice, or no quote available — with net loss, overcharge rate, and a by-cause/by-destination breakdown computed automatically. From there, a dispute can be built, sent to EPG as a CSV with a plain-English cover summary (optionally drafted straight into Gmail), and tracked through to credited or rejected. A nightly job re-checks unverified parcels automatically, so the backlog shrinks on its own instead of waiting on someone to remember.

Ship Logger Invoice Audits page showing net loss, overcharge totals, a per-invoice chart, and open EPG disputes

Problems that went unnoticed until a customer complained

A shipment that's been in transit too long, stuck without a status update for a week, or quietly costing more in shipping than the customer actually paid for it previously had no way to surface itself — someone had to think to go looking, and usually the first sign of trouble was a customer asking where their order was.

The fix: an Exceptions page sweeps every shipment daily for three categories — carrier exceptions, stale shipments with no status movement, and shipping losses where what the customer paid for shipping doesn't cover what the carrier actually billed — and a daily email digest puts the same list in an admin's inbox without them needing to check the app at all. Each problem can be dismissed once it's been looked at, but a dismissal is scoped to that specific problem category, so a shipment that develops a new issue later still shows up again rather than being silenced for good.

Ship Logger Exceptions page listing shipments where shipping cost more than the customer paid, with tracking, order, and loss amount

How it was built

Ship Logger is Next.js (App Router) and TypeScript on Vercel, with Postgres via Drizzle ORM — Supabase in production, through its transaction pooler rather than a direct connection, since each serverless invocation opens its own short-lived connection and the direct-connection limit exhausts fast under concurrent load. A few decisions came directly out of running a real warehouse desk rather than a typical CRUD app:

  • The scanner is treated as a keyboard, carefully. A document-level keystroke listener (not a focused input, which breaks the moment someone clicks elsewhere) buffers scans in a ref rather than React state, since per-character setState thrashes at scanner speed, and a configured prefix/suffix in the scanner's own firmware backs up the timing heuristic.
  • Database-level concurrency guards, not just application checks. A partial unique index enforces at most one open shipping session at a time, and another rejects two scans racing to claim the same sequence number in a session — both the kind of race condition that only shows up once, at the worst time, without a hard constraint underneath the application logic.
  • An unofficial carrier endpoint, used honestly. The free ePost Global status feed is undocumented and could change or disappear with no notice, so the integration is built to fail soft: a parser anchored on the stable JSON structure rather than fragile page markup, and a failure that degrades to a visible banner rather than taking anything else down.
  • Soft-delete and short-lived undo everywhere it matters. A deleted shipment moves to a trash view before a 30-day purge makes it permanent, and a "Reset Day" action snapshots the session first so an accidental reset can be restored rather than simply gone.

The Shopify side is a custom app used purely as a server-side API credential via OAuth client-credentials — no interactive install flow, and no Shopify staff seat for anyone on the packing floor. ShipStation supplies real per-parcel weight, dimensions, and cost once a label exists, which is what makes both the invoice audit and the shipping-loss exception possible at all, and Resend sends the daily exception digest without anyone needing to check the app.

Where to see it

Ship Logger runs live at ship-logger.vercel.app as OTC Shoppe Express's day-to-day shipping desk — it's an internal operations tool behind PIN sign-in, not a public product, so the screenshots above use placeholder orders, names, and tracking numbers rather than real shipment data.

Keep reading

Mai-O-Mailee's Authentic Hmong seasoningportfolio

Mai-O-Mailee’s

Mai-O-Mailee’s, a Hmong-owned business, sought to share its culturally rich food products with a wider audience but was limited by an ineffective website. Their online store struggled to convey the value of their **authentic Hmong seasoning**, facing issues with brand storytelling, user navigation, and search visibility. Through a complete Shopify redesign and a targeted SEO strategy, we helped transform their digital presence. The new site celebrates Hmong culinary heritage while creating a seamless customer experience. This project helped Mai-O-Mailee’s connect with new customers, build their brand, and drive meaningful business growth.

Read
Magical Claws arcade birthday party tulsaportfolio

Magical Claws

Hmong entrepreneurs Shoua Thao and Kao Lor launched Magical Claws arcade but struggled with a low $20 average order value and lacked an effective online booking system. Hmong Network provided comprehensive web design and business consultation. We restructured their pricing, integrated a seamless Shopify POS, and built a user-friendly booking platform. This strategy transformed their business, increasing the average order value to over $70. Magical Claws is now a thriving local destination, successfully capturing the market for an arcade birthday party tulsa and demonstrating how strategic digital solutions drive real-world growth for community-focused businesses.

Read

What we do

Packages

The work

Start here

Which are you?
Or just call (918) 777-4186