[CASE STUDY 07]

SeeTrack Field-Force & Distribution Platform

A field-force and distribution platform for a distributor selling to retail shops in Pakistan: geofenced shop visits, delivery and cash collection, a warehouse stock ledger and double-entry finance. I built ten of its 31 modules, 334 of its 474 API endpoints, and the controls that keep its stock, cash and access correct.

Role
Full-Stack Engineer — ten modules, end to end
Timeline
Jul 2026 – Present
Status
Live · finance pre-launch
Stack
TypeScript, Node.js, Express +8
SeeTrack architecture: salesmen, riders, office staff and the admin use Next.js screens scoped by role; an Express API checks a JWT and then a permission matrix whose seed is parity-tested on the 228 endpoints that existed before the move, in front of field operations, a stock ledger that moves every piece through one function, and a finance module in pre-launch, where final approval is the posting; crons run in process over one MongoDB Atlas database

* FIELD, STOCK AND BOOKS

SeeTrack: Field, stock and books

[AT A GLANCE]

OWNED
Ten of 31 modules end to end, 334 of the platform's 474 API endpoints: warehouse and stock ledger · collections · finance · permissions · analytics · targets · performance flags · region sales · item performance · account freeze
ALSO BUILT
Geofenced check-in, features and fixes across the base modules, from returns against an invoice to client statements, and the test suite: 1,640 cases in 73 suites, where the base build had none
USERS
Eight roles: salesmen and riders on phones in the field; the admin, managers and warehouse staff in the office; an accountant and a finance manager once finance goes live
STATUS
Field operations are live. Finance is built through the month close and in pre-launch: its ten automatic postings ship switched off, to be turned on one event at a time after acceptance
NOT MINE
The base platform: 21 modules first built by a second engineer in March and April 2026, including auth, orders, visits and attendance, with the CI and deployment setup. The finance, warehouse and permission rules come from the client's specifications. Maps and routing come from OpenStreetMap and OSRM, navigation from Google Maps

[STACK]

  • TypeScript
  • Node.js
  • Express
  • MongoDB
  • Mongoose
  • Next.js
  • React 19
  • Leaflet
  • Chart.js
  • PM2
  • GitHub Actions

[01] The problem

Visits, stock and cash nobody could check

A distributor works away from its office: salesmen visit shops and book orders, riders deliver and collect cash, and stock moves between warehouses. In the base platform, a visit's GPS was never compared with the shop's location, and an edit could mark a visit complete with no proof at all; stock was a single number per product that orders drew down and only an admin's typed figure could raise; and there were no books. Visits, stock and cash all had to become checkable, and money had to reach a ledger only through a controlled posting.

[02] The constraints

What a live distributor ruled out

  1. Correct with or without transactions

    Production runs on MongoDB Atlas, where multi-document transactions work; the test and migration databases are standalone, where they do not. Correctness had to live in idempotency keys and compensation, using a transaction only where one exists.

  2. A deploy may not change who can do what

    Role checks were hard-coded at nearly 200 route call sites, and the admin app kept its own copy that disagreed with them. Moving to one permission matrix had to keep every existing grant as it was, apart from changes made on purpose.

  3. Money switches on one event at a time

    Finance had to land in a running business without disturbing it. Every automatic posting ships switched off, so finance can be deployed long before it is turned on, one event at a time, with the nightly control checks watching.

[03] The approach

How it was built

The client's specifications set the rules: what a stock movement may do, that the admin's final approval is the posting, who may do what. My part was making those rules hold: every stock movement goes through one guarded function with a replay key on every row, every finance posting through one engine, ten control checks run every night, and the permission matrix is held to a parity test against the access that existed before it.

[KEY DECISIONS]

  1. [01]Put every stock movement through one function with a guarded update and a replay key per ledger row.
  2. [02]Moved stock out of the source warehouse at transfer approval, so goods in transit cannot be sold.
  3. [03]Implemented the specification's rule that the admin's final approval is the posting, with one engine writing a balanced journal for all seven kinds of finance document.
  4. [04]Ran ten control checks against the ledger every night, and let any drift block the month close.
  5. [05]Replaced nearly 200 hard-coded role checks with a permission matrix, held to a parity test over the 228 endpoints that existed before the move.

[04] The trade-offs

Where the books beat convenience

  1. [01]

    One function moves all stock, keyed for replay

    Instead of
    Rely on a database transaction for correctness, which production supports
    What it cost
    Every movement needs a compensating path, and a retry has to recognise its own earlier attempt.
    What it bought
    The same code is correct on Atlas and testable on a standalone database, and a replayed movement is a no-op.
  2. [02]

    A stored balance beside an append-only ledger

    Instead of
    Keep only the ledger and sum it whenever stock is read
    What it cost
    Two records must agree, and a balance that disagrees with its own ledger needs a person to resolve.
    What it bought
    Never-below-zero is one guarded update on the balance, not a read-then-write race over the ledger.
  3. [03]

    Transferred stock leaves at approval, not at receipt

    Instead of
    Take it off the source warehouse when the goods arrive
    What it cost
    A long transfer can trip a false low-stock alert.
    What it bought
    Goods on a truck cannot be sold from either warehouse.
  4. [04]

    A stock count applies the difference, not the counted figure

    Instead of
    The specification's literal rule: overwrite system stock with the count
    What it cost
    Lines that moved between submission and approval need a person to review the drift.
    What it bought
    Sales, transfers and receipts made while a count waits for approval are not erased.

[05] The build

What SeeTrack is made of

  • [01]

    A check that the visit happened at the shop

    Where a shop has a saved location, salesmen must check in within 150 m of it, an order taken on a visit must be booked while checked in, and checkout still takes a shop photo, a selfie and their GPS position. Time on site is recorded with a 30-minute overstay flag, a warning comes before a skipped visit drops them below 75% completion, and a salesman not checked in by 12:30 is frozen.

  • [02]

    One door for every piece of stock

    Receipts, orders, transfers, damage and counts all move stock through one function: never below zero, all lines or none, a replay key per ledger row and an audit row per change. Stock sits in three buckets per warehouse, sellable, in transit and damaged, and every balance is checked against its ledger each day.

SeeTrack: every stock movement passes through one function that keeps a balance and a ledger row per change and never lets stock go below zero; all seven kinds of finance document go to the admin for final approval through an optional review their maker cannot perform, and that approval posts a balanced journal entry; field money and returns post only once their switches are on; a reconciliation engine by Pakistan business day and a clean check before each month closes; finance is in pre-launch

Finance documents onto the books

[03]

Finance documents onto the books

All seven kinds of finance document, from vouchers and bills to payroll runs and staff advances, go to the admin for final approval through an optional review their maker cannot perform. That approval posts a balanced double-entry journal across a seeded chart of 53 ledgers, and a refused posting stays on the document with its reason. Every finance report exports to PDF, Excel and print.

  • [04]

    Ten checks before a month can close

    Every night, ten control checks prove the books against the records behind them: what shops owe, what riders hold, online payments in transit, stock on the shelf, in transit and out for delivery, goods received but not billed, what is owed to suppliers and staff, and the advances staff owe back. Any drift blocks the month from closing, reported with its account, its amount and the day it first appeared.

  • [05]

    Permissions as data, access held in place

    The client required an admin-editable permission matrix. I seeded it from the backend's own route guards, replacing nearly 200 hard-coded role checks, kept admin outside it so nobody can lock themselves out, and gave people with several roles an admin-defined profile. A parity test checks the seed against who could reach each of the 228 endpoints that existed before the move.

  • [06]

    Reports that carry their totals

    Per-employee analytics, monthly targets and region-sales drill-downs, with grand totals over the whole dataset on the report tables, carried into every export.

[06] What broke

And what fixed it

  1. !01

    The late-start freeze never fired

    In production, the rule exempted anyone with no visits generated for the day. Visit generation had stopped three weeks earlier, so from launch every salesman was exempt every day and late starters kept taking orders after 12:30. The exemption came out two days later, and an idle generator now shows up as a count.

  2. !02

    Shop balances ignored returns

    A change of mine left returns out of what a shop owed, so the rider's screen overstated each balance by the value of every return, and the recovery cap, set from that figure, could let a rider collect money the shop did not owe. Building the receivables control check surfaced the gap, and the fix matches the ledger line for line.

  3. !03

    Staff data readable through the APIs

    The base platform's product catalogue carried its creator's salary, home address and phone to salesmen and riders, and changes of mine added the last purchase rate to it and widened an unscoped visit list to more roles. Order taking now uses a picker that returns only what an order needs, visits are limited to the staff a caller may see, and tests assert both.

  4. !04

    Stock value counted twice on the books

    Before finance went live, a reversal copied the source of the entry it undid, so a query for a document's live posting also found its reversal. A test written before the fix showed two edits to one goods receipt leaving 7,200 in inventory where 6,200 was right.

[07] The result

What was verified before release

  • 119

    Access errors caught pre-release

    * endpoint–role pairs: 83 lost, 36 gained

  • 10

    Nightly control checks

    * finance, pre-launch; drift blocks the close

  • 28 / 30

    Finance acceptance scenarios

    * from the client's specification, under test

  • 1,640

    Automated test cases

    * in 73 suites; the base build had none

[HOW THESE WERE MEASURED]

These are pre-release verification results, not business outcomes: the distributor's volumes are its own, and nothing was load-tested. The 119 comes from the parity test's first run over the 228 endpoints that existed before the matrix; the control checks and acceptance scenarios belong to the finance module, built but not yet live; test and endpoint counts are static, at the repository state of 1 October 2026.

[08] What I’d do differently

Honestly

I'd write the suites before calling a module done. The permission tests came afterwards and found 119 access errors the diff had hidden, and the suites still run by hand rather than in CI.

Written by Faizan Amir

Role on SeeTrack: Full-Stack Engineer — ten modules, end to end

Last reviewed

Need something like this built?

Next case study [08]

Human-in-the-Loop Scheduling Agent

Read the case study →

AVAILABLE FOR SENIOR ENGINEERING WORK + REACT + NEXT.JS + NODE.JS + PYTHON + RAG + AGENTIC AI