‹ Back to FleetView
NORTHFLEET
Changelog
FleetView Transport Manager — prototype release history
v0.133.0
22 August 2026
Current
- Con note splits (#281). One con note can be split into lettered parts — CN1042A, CN1042B, CN1042C — across different trailers, drivers or loads while staying under one purchase order. A part is an ordinary consignment record carrying
parent and splitLetter, not a new collection, so the dispatch board, the schedule, the driver run sheet and the traffic light all read it with no change. The PO, the customer reference and the price are inherited from the parent, and the parent’s status rolls up from its parts.
- A part is withdrawn, never deleted — it stays on the record and is drawn hatched, because a part that was quoted and then pulled is evidence somebody may ask about.
- A part cannot itself be split, and the refusal is printed in the form as the writer’s own sentence rather than shown as a toast that slides away while you are still reading it.
- The invoice and record-count disclosures sit above the list at body-copy weight, not as small print under a table — the same correction
.cmp-sr-axis already carries.
v0.132.0
22 August 2026
- NewThe database API can now answer on api.fleetview.northfleet.com.au, matching the site’s new name. Set up once, by hand, then left alone. The site is moving to fleetview.northfleet.com.au; the API it talks to was still on a raw machine-generated Amazon address. There is now a one-off setup script (infra/provision-api-domain.sh) that creates the name and points it at the existing API, plus a step-by-step runbook. Nothing about the app changes and no backend deploy is involved — the API keeps working exactly as it does today until somebody runs it, and it can be run before the certificate is ready without doing anything at all.
- ChangeIt is deliberately kept out of the backend deploy, because putting it there could take the API down during a routine release. The backend is deployed by a manual workflow whose settings are sticky: the value you type is the value that sticks, so a release that simply accepted the defaults would blank a setting somebody had filled in. If the domain lived there, that would delete the mapping and take the API offline while every browser was still pointed at it — a total outage caused by an ordinary deploy. This is not a theory: overnight vehicle-position recording was silently switched off exactly that way once already. So the domain lives with the other one-off account setup, which no frequent deploy touches.
- ChangeTwo certificates are needed, in two different regions, and the requirements are the exact inverse of each other. The website’s certificate must be in Virginia (us-east-1) because that is the only place the CDN reads one from; the API’s must be in Sydney (ap-southeast-2), because an API of this type only supports a regional address and a regional address needs the certificate in its own region. Each service rejects the other’s certificate, so one cannot be reused for the other. This is the single easiest thing to get wrong here, so it is written as a table in both guides rather than buried in prose, and the setup script now refuses a wrong-region certificate up front instead of letting the deploy fail several minutes later with a less obvious message. The DNS record has the matching trap: it must point at the regional target address the setup prints, not at the API’s own address, which will not answer and fails the security handshake.
- ChangeRecorded as a rule: the old API address can never be retired, because delivery photos and signatures already point at it. A delivery photo’s web address is stored on the consignment record at the moment it is captured, not worked out later — so every photo, signature, licence image and completed form captured before the move carries the old address forever. Both addresses serve at the same time, so nothing breaks and the switch-over is fully reversible; but these are proof-of-delivery and audit records kept for years, and retiring the old address would make them all fail to open, quietly, while the records still looked complete on screen. Stated as a rule in both guides rather than as a footnote, with the safe procedure if the address ever genuinely has to change.
- ChangeThe one-off infrastructure files are now checked automatically, which they never were. The build already checks the backend’s own infrastructure file and every workflow file, but the two files that create the website hosting and now the API address were checked by nothing — so either could have been malformed and nobody would have found out until they were being run during a new-account setup or a domain cutover, which is exactly when a surprise is least welcome. It also catches one specific trap: a file where every item is optional is rejected outright by Amazon, and that is a live hazard here. Confirmed to catch all three faults it claims to.
- ChangeA security question about training packages was reviewed and deliberately left alone, with the reasoning and the date recorded. Uploaded training packages are served without a password by necessity, and on the new address they will come from a northfleet.com.au name rather than an unrelated Amazon one. It is recorded as accepted, not fixed, because there is currently nothing for it to reach — the app keeps no browser sign-in cookie of any kind — and because that changes when single sign-on arrives, which is when it will be revisited rather than now.
v0.131.1
22 August 2026
- ChangeThe address the portal QR codes point at is now a deploy-time setting, so moving the site to a custom domain cannot leave drivers installing the app from the old one. No backend deploy needed. The site’s public address was written into the code, and it feeds four QR codes — two on the sign-in card, two on Settings — as well as every shipment tracking link and quote-acceptance link sent to a customer. Northfleet is moving to fleetview.northfleet.com.au, and the old CloudFront address keeps serving, so nothing would have looked broken: the codes would simply have gone on pointing at the old one. That matters because a driver scanning it installs the tablet app from a different address than the office is using, and the browser keeps its saved data separately per address — so that tablet forgets which one it is and enrols itself as a second entry on the device register, on the one register whose whole purpose is knowing which tablet captured which delivery photo. The address is now read from the deploy, defaulting to today’s behaviour, and it is set from the same setting the deploy already uses to verify the live site rather than a second one that could disagree with it. If it is not set the deploy is not blocked — the old address still works — but it says so in the log, because after the move those links would be pointing at the wrong place.
- ChangeAnd it is deliberately not read from “wherever this page is being served from”, which is the obvious simplification and is wrong. These codes and links are read on somebody else’s device — a driver’s phone, a customer’s email. On a developer’s own machine the page is served from localhost, so deriving the address that way produces a QR code that no phone can use and a tracking link a customer cannot open. The reason is now recorded next to the code, and the automated check decodes the rendered QR code back to a URL and asserts it is the published site and not the local one — so a future simplification along those lines fails rather than shipping. That check went from 42 to 80; reverting the setting reddens 12 of them, and switching to the served-from address reddens 4, which print the localhost URL they would have put in front of a driver.
v0.131.0
21 August 2026
- ChangeAsking the daily summaries for a very wide window can no longer cost thousands of database reads. Needs a backend deploy. The daily per-asset summaries are stored a day at a time, so reading a window meant one database query per day — and the ceiling on how far back you may ask is ten years. Measured on the real code before the fix: a single request for a ten-year window issued 3,651 queries inside one call (31 for 30 days, 91 for 90). It now goes through the same bounded reader the speeding log and the crossing log were moved onto in the last release, and costs at most 128. That release deliberately left this one alone, and said why: it had no way to describe a partial answer, so capping it without one would have been the silent truncation the whole change existed to refuse. This adds the vocabulary first and then the cap.
- Fix…and in the same code, one dead database partition was throwing away seven-eighths of a good answer. The read fanned out one query per day and waited for all of them, so a single throttled partition out of eight failed the entire request — the route answered 500 with no assets at all where seven days of eight had arrived perfectly. It now keeps what came back and names what did not, which is the same call the speeding log already made. Also replaced: the window was built by stepping forward an hour at a time — 87,601 steps at the ceiling, against 3,651 for the shared reader, and 2,161 against 91 at the 90 days this app actually uses. That was a correctness fault and not only a cost one: a forward walk that stops collecting cannot say how many days were asked for, which is precisely the number a partial answer has to report.
- NewFive screens now say how much of the window they actually read — and there are three answers, not two. Every figure derived from those summaries is a rate over a denominator: the coaching before-and-after comparison, the 90-day long-run panel whose output is a disposal conversation, Fleet Overview’s utilisation and safety rates, the speeding leaderboards and the days-idle column on Lost Revenue. A short read that did not say so would put all of them over a window nobody read. So: a confirmed complete read says nothing extra (a paragraph confirming everything is fine is the noise that teaches people to stop reading a panel); a read that came back short is a warning carrying the server’s own sentence about what is missing, and states that what is missing is unknown, not zero; and a read that does not report completeness at all gets its own third, muted wording. That third case is the normal one until the backend is deployed — the live route does not report this yet, so every one of those screens will correctly say so rather than claiming a complete read. Reading “not stated” as “complete” would be the original fault arriving from the other side, on the live site; reading it as a failure would cry wolf on every page load. Neither. One reader, five screens, so the sentence cannot drift five ways.
- FixA trailer out on hire was being counted as a trailer sitting idle. No deploy needed. Hired-in work is deliberately excluded from our own asset figures — it is not our fleet working — but the idle count was simply total days minus days we used it, so a day the asset was demonstrably out earning money with a subcontractor was charged to it as a spare day. Measured on a lent trailer: 0 days worked, 6 idle, while it was out on hire for one of them. This panel’s output is a disposal conversation, and the error ran in the direction that flatters disposal. There are now three columns because there are three facts — days our fleet worked it, days it was out with a carrier, days it was genuinely spare — and they need three different phone calls. The day sets are combined rather than the counts subtracted, because we lend a trailer out in the morning and use it ourselves in the afternoon, and subtracting counts turned that single day into minus one. A row with nothing on hire shows a dash, not a zero: “no hired-in run named it” is not the same claim as “it was out for zero days”.
- FixA revocation raised against one truck could release a different one, and tell the driver the wrong truck’s name. Asking a tablet to let go of a truck is modelled as a request precisely because the office cannot reach a tablet in a dead spot — and a tablet can be out of coverage in the Pilbara for a day, which is long enough for somebody to move the glass into another cab. The tablet used to drop whatever truck it was in now and then show the driver the truck named in the request, so it released the wrong binding and the one panel telling the driver why their run sheet changed named a cab they had never been in. It is now refused, not relabelled: quietly correcting the label would still be releasing a binding nobody asked about. Nothing is released, the office’s request is marked as unactionable on the record — so it stops reading as a tablet that merely has not synced yet, which is somebody waiting for something that can never happen — and a new request can be raised against the truck the tablet is actually in. The driver sees nothing, because nothing about their tablet changed.
- FixThe attendance register stopped opening on whoever you looked at last time. Drilling into one person’s attendance and then leaving the screen left that drill-down remembered, so coming back opened on them again — which reads as the wrong screen rather than as a remembered place. Reset on arrival only, never on a repaint, because the screen redraws itself on every filter keystroke. Deliberately not changed: the screens that remember which view or which day you were on. Remembering a view is wanted; remembering one record is not.
- ChangeOne automated check stopped guessing at how the schedule groups its rows. It built its own idea of which lanes belong to a depot by filtering the data, but the board pulls every projects-stream lane out first, before the depot split — so the two only agree while no projects lane happens to share that depot. They agree on today’s data; moving one lane to a projects stream, which is ordinary because the two divisions share drivers, makes the board correctly say 4 while the check still insists on 5. It would have gone red describing correct behaviour, which is the ninth time this project has paid for a test re-deriving something the product derives differently. It now reads the grouping off the screen, where the product publishes it.
- ChangeThe backend check total is now a rule rather than a number, because three different figures had been published for the same code. “Each suite’s own printed total” sounds like a method and is not one: three suites report scenarios rather than checks, two print no number at all, and one prints its summary on a line that itself carries a tick. Counting them one way gives 1,211, another 1,225, and a third — a single uniform tick count, the obvious simplification — gives 1,243, because one suite deliberately does not tick per check. All three were honestly measured; they were answering different questions. The rule is now written down once, mechanically, so the number can be reproduced rather than trusted, and every earlier figure is reconciled against it in the developer notes. Measured on this build: 5,746 checks in the dependency-free suite, 1,366 across all 19 backend suites (7,112 together), and 58 browser suites — one of them new — all green. The two branches in this release were built on the same base, so their own figures of 5,690 and 5,698 are independent deltas that cannot be added; the merged tree is what was counted.
v0.130.0
20 August 2026
- NewThe words everyone used in the scheduler session are now the words the app uses — and a new con note carries its quote’s own number. No backend deploy needed. The 14 August session settled a vocabulary — Quote · PO · Consignment · Con note · Split · Component · Item · Manifest — and six of the eight already existed in the app, two of them under a different name. So this adds readers, not tables: no new collection, no new field, nothing to migrate. A con note is the same record as a consignment, ratified rather than duplicated; a component is what the app has been calling a leg, renamed in language only because renaming the field would mean rewriting every record already on file for no change in behaviour. A component now says which of pickup, line haul and delivery it actually covers — multi-select, so a driver doing all three shows all three, and one driver doing the lot reads as one shot. And Q1062 becomes CN1062: a con note born from a quote takes that thread’s number, so the number somebody reads down the phone is the same number at every stage. Nothing already on file is renumbered — PODs, invoices and service records all hang off the existing ids, and re-pointing them would attach one job’s paperwork to another.
- FixOne claim from that session is not true of the code, and the app says so rather than half-building it. “One PO rolls up to one invoice” was on the list; invoicing keys one invoice per con note, so a purchase order spanning two con notes still produces two invoices. Rather than leave that to be discovered later, every answer the new purchase-order reader gives carries an explicit “this does not roll up” flag, so nothing can quietly be built on an assumption the code does not honour. The roll-up itself is tracked separately and stays open. The reader also keeps three answers apart that need three different phone calls: no PO recorded (which is the one to chase, in the app’s existing words), covered by a standing annual PO, and there is a reference but we cannot say it is a PO — the last because that box can legitimately hold the customer’s own job number, or our own thread number, which is not a customer PO at all.
- NewA traffic light on the schedule, readable without hovering and without relying on colour alone. Each run on the board now shows how its con note is actually going — per phase, so pickup, line haul and delivery are separate answers rather than one blended status. The colour is deliberately not the cell background: a run’s background already means its type, so painting status there made a mandatory rest day read as an exception and a fatigue day read as a completed delivery. Status gets three channels of its own instead — a thin strip, a glyph and a letter code on every chip, and a ring for red only — so a chip’s identity never depends on the fill and the board is readable to a colour-blind reader. Late is measured by day, not by time of day, because the times on this board are nominal: an earlier attempt to use them produced 86 findings on a board where nobody had flagged anything. “An error” means the con note is marked failed and nothing else, kept narrow so red never lands on correctly arranged work.
- Change…and it states its own horizon, because a traffic light on a nine-day board is not an overdue sweep. The question behind this was “why is this job from last week still showing?” — and that describes a record which is not on the board at all: the board shows yesterday, today and seven days ahead, so no colour anywhere can answer it. The screen therefore says in full what span it covers, that this is not a complete list of overdue work, and that nothing here can turn red for a job that has dropped off the window. The list that would answer it is deliberately not built here, because it is a list and not a colour. One thing was also removed after measuring rather than shipped on the assumption it would fit: a summary pip on each run needed 125px where the cell renders at 121px, wrapping every run onto three lines and adding up to 33px of height to each of 271 runs. Nothing is lost — the summary is derived from the chips that are already there.
- NewHand the rest of a job to another driver without the first driver’s day going blank. No backend deploy needed. Dragging a job onto another driver moves it, so the original driver’s box empties and reads as though they did nothing — “Toby goes empty again”. You can now hand over the remainder instead: the part already done stays with the driver who did it, the rest becomes a component on the new driver, and the trail shows who captured what, in the order it happened. The trailer carries across; the prime mover and driver do not. Two refusals are deliberate. Where the driver has stamped nothing, this is a reassign and not a hand-over — allowing it would leave a green box on somebody who has done nothing, which is the same bug this exists to fix, wearing the other hat. And a component whose changeover is already stamped cannot be split. The driver’s own screen shows the trail read-only, and not at all on a single-driver run, where it would only repeat the stamps directly below it.
- FixBuilding that found a real fault in the same area, on a compliance record, running the wrong way. Splitting a component whose changeover had already been recorded moved the stamp and not just the numbering: measured on a two-component relay, the driver who had recorded taking the trailer lost their own take-over, and a driver who had done nothing gained it — dated 10:35 at a depot they had never been to — while the genuine receiver was pushed down the chain with nothing captured and shown as blocked. That is a record saying one person was somewhere another person was, which is the mirror image of the blanked-driver problem above and worse, because it is evidence. It is now refused by name, and the refusal is tested in both directions so that the legitimate case it sits next to — a driver taking a trailer where the other end has not synced yet, which is normal out of coverage — is not caught by it.
- ChangeA test that had been red since the previous release, and was red for the right reason. Changing the number prefixes to
Q/B/CN broke three checks in the suite that guards “one record, one number” — and the product was correct in all three: the checks matched the old format literally, requiring a hyphen, so Q1042 / B1042 / CN1042 was reported as three different numbers when it is plainly the same digits at three stages. They now test the claim rather than the format, and two further holes were closed while in there: one check was satisfied by the raw database id, so it would have passed on a screen that threw away the whole point of the feature, and another compared only neighbouring pairs, so a numbering where the con note reused the quote’s prefix passed. That suite goes from 37 checks to 40. Across this release: 5,642 checks in the dependency-free suite (up from 5,277), all 18 backend suites green, and 57 browser suites — one of them new — all measured by running them on this build.
- FixAnd the one check still red on this release’s own gate — a test whose clock could straddle midnight. No deploy needed; no product code changes. The backend speeding-log suite placed its samples a fixed number of minutes before “now”, so for roughly 00:12 to 01:49 local they fell either side of midnight and the fixture described a day the recorder cannot produce — red for that window every night, on every branch including
master. Its clock is now pinned to local midday — skewed rather than frozen, installed before the code under test loads — so no fixture can reach a day boundary in any timezone, and one added later inherits it. Folded into this release rather than shipped separately. That suite goes from 186/159 checks per storage layout to 199/172, which is why the backend figure in the developer notes moves to 1,211 and the release total to 6,853.
v0.129.0
20 August 2026
- FixThe check that runs before a backend deploy was testing eight-eighteenths of the backend and saying nothing about the gap. No deploy needed — it protects the next one. The Verify before deploying gate and the ordinary build each carried their own hand-typed list of backend test suites, and the two had drifted apart: the gate ran 8 of the 18 suites on disk, and the ten it skipped included the only test file the previous release changed. So the gate on the deploy that shipped that release never ran the tests for it. It passed when somebody ran it by hand, which is diligence and not a control. Both now read one list, generated from what is actually on disk, so a new suite is covered the moment the file lands and there is no list to forget. Gate coverage goes from 182 automated backend checks to 1,185. What that is worth is not theoretical: deliberately reintroducing an old fault — a truck banking a frozen GPS fix as a real speeding offence, which would put a fabricated over-limit run on a compliance record — was green on the old gate and red on the new one. The build also now checks that its own workflow files parse, and that every test suite on disk is actually wired in or named as a deliberate exception with its reason — the sweep that caught four suites sitting green and unrun is now a check rather than a habit.
- ChangeAsking the speeding log or the crossing log for a very wide window can no longer cost thousands of database reads. Needs a backend deploy. Both logs are stored a day at a time, so reading a window meant one database query per day — and the ceiling on how far back you may ask is ten years. Nothing asks for that today, but a “show me everything” report would, and a single request for a ten-year window was 3,651 queries inside one call; narrowed to a list of trucks it multiplied again, to roughly 186,000. Both now cost at most 128. Two things it is careful about. A window wider than that comes back as the most recent stretch and says so in its own words — how many days were asked for, how many were read, and that this is not a statement that nothing happened before then — rather than quietly handing back a subset. And narrowing to a list of trucks never costs you a qualified answer: past the budget it reads the whole day and filters afterwards, which is wider but far cheaper, so 200 trucks over a week is 8 queries instead of 1,600 and still a complete answer. A record dated in the future — a crossing is timed by the tablet that files it, so a bad clock can produce one — is now left out, counted and named as a clock problem rather than shown as a finding. Until the backend is deployed none of this reaches the live API; the wide-window cost is unchanged there.
- FixA test that quietly stopped testing anything, and the fixture rule that makes that possible. One automated check picks work off the generated roster, and on a Saturday the roster gave it exactly three candidates against its own minimum of three — one fewer and it stopped early having tested nothing, which is a check that reports success by not running. It now builds the work it needs instead of fishing for it, taking its margin from 0 to 13; the sibling check for relay legs got the same treatment (2 to 15) and had a second fault besides — the fall-back it relies on is dead on a Saturday, so half of what it claimed to cover was unreachable one day in seven. This is the eighth time a check here has passed or failed on the day of the week rather than on the code, so the underlying rule is now enforced by the tooling rather than remembered: declaring a driver’s day for a test is a single call that clears both halves of that day, and the half-done version that caused the previous seven is no longer possible to write. The engine-room checks were moved onto it and grew from 178 to 186.
- ChangeEvery test count in the developer notes was re-measured by running the suites. Four had gone stale — two of them left deliberately for whoever could see all the work at once. Nothing in this release changes a screen: 5,277 checks in the dependency-free suite, 1,185 across all 18 backend suites and 56 browser suites, all measured on this build, all green.
v0.128.0
20 August 2026
- ChangeSpeed Alerts now ask the recorder for the over-limit runs it already worked out — the whole tracked fleet instead of the busiest 120 — and fall back to the old way whenever it cannot answer. v0.126.0 taught the recorder to derive the runs as it writes each position; nothing read them. Speed Alerts, the Events screen and Fleet Overview now ask for that log first, which replaces a week of the fleet’s raw speed samples and a long calculation in the tab with one small read, and removes the cap: where the recorder answers, every tracked asset was checked rather than the worst 120. The fall-back is deliberately the cheap direction — no API configured, the route not deployed, a failure or a timeout all leave every screen deriving its own alerts exactly as it does today, because a speed alarm that stops working because a new route is not out yet is worse than one measured the old, expensive way. The 120-asset limit has therefore not been removed; it is what the page uses on the day the recorder is unreachable, and on that path the screen says so in the first sentence rather than letting a capped check read as a complete one. One further fix it needed: the two methods sample the same drive differently, so the same offence used to arrive under two different reference numbers and could be logged twice — a run that overlaps one already recorded for that truck is now recognised as the same stretch.
- New…and the page will not claim it checked everything unless it was actually told so. “There is no cap on this path” and “this read came back whole” are two different claims, and only the first is free. The alerts screen now reads what the recorder says about its own answer and renders three different things: a confirmed complete read (nothing was left unchecked); a read that came back short, where what is missing is unknown rather than zero and the recorder’s own sentence naming what is missing is printed as written; and a recorder that does not report this at all, which is stated as its own third answer and never quietly counted as complete. An empty list is the dangerous one: “we looked and there was nothing” is reserved for a confirmed complete read, and anything else says in words that this is not a measured zero. Fleet Overview keeps showing the real count on a short read — that number is right — but adds an item saying the count is a floor rather than a total, because that board goes on a wall nobody interrogates.
- FixA failed read of the speeding log used to answer “no speeding”. Needs a backend deploy. The route caught its own failures and answered success with an empty list, on the reasoning that the app would work the alerts out for itself instead. It would not: an empty list that says it succeeded is indistinguishable from a fleet that drove within the limits, so a database failure would have printed “we looked, and there was nothing” on a compliance screen. Found by the first thing that ever read the route, ten minutes in. Every answer now says which of three it is — here is what the fleet did, we looked and there was genuinely nothing, or we could not look — a read that returns nothing at all now fails outright instead of reporting success, and a read that came back part way is named as part way rather than presented as the whole week. The recorder’s own limit on how many runs it files in one pass is also no longer silent: what it dropped is stamped on the records it did write and reported with the read, so a busy day is a named partial record rather than one that looks complete. And a first pass whose writes all failed no longer marks that day as caught up — it used to, which quietly lost the rest of that day’s runs for good.
- ChangeUntil that backend deploy lands, the alerts page saying it cannot confirm the read was complete is the correct and expected wording, not a fault. The deployed route still answers the old way, so it reports none of the completeness information above — and a response that does not mention it is an older recorder, not a complete read. Nothing in the app treats the absence of that information as permission to claim a full check; that is the whole point of the change, and the app deliberately behaves this way on the live site today. Once the backend is out, the same screens start showing the confirmed-complete wording without any further release. Both halves are pinned by tests: 90 more automated checks in the dependency-free suite (5,277 in total, all measured by running it), the recorder-side suite grown to 129 checks in the current storage layout and 124 in the legacy one, and the browser check for these screens grown from 48 to 127 — driven through the real network layer, because a request that fails outright and one that reports success while carrying an error look identical by the time they reach the screen.
v0.127.0
20 August 2026
- NewSubcontractors and grey fleet are on the schedule — and they are counted apart from our own capacity. Needs a backend deploy before the carrier list persists. When the work goes out to a subbie or somebody drives their own ute, that row can now say so on the board, so a run is never quietly attributed to a truck we own. Each row names who is carrying it, and the rail says how many of the hired-in rows are actually booked. Two rules are deliberate and stated on screen: we hold no licences, medicals or inductions for somebody else’s driver, so those rows show a hatched “no record held” rather than a green tick we cannot stand behind — and that is not a claim their paperwork is out of date; and utilisation excludes hired-in work and says so, because counting a subbie’s day as ours would flatter every figure on the page. Projects rows — our own capacity managed on another board — are shown so a driver cannot be committed twice, and are counted in neither figure. Carriers are added, edited and archived like any other master record, so an id is never re-used and last month’s runs still name the carrier that did them. Until the backend is deployed the carrier list is held on the machine that entered it and will not appear elsewhere. Also fixes two long-standing faults it uncovered: a lane with no driver on it threw an error that painted over the whole dispatch board, and the empty-legs panel was offering a hired-in row’s return leg as one of our own backloads.
- NewThe office can finally see the in-cab tablets. Needs a backend deploy before the register persists. Which tablet is in which truck used to be known only to that tablet, so nobody could answer “which device is in NF835”, see that one had not been heard from in a week, or ask one to let go of a truck. Each tablet now puts itself on a register when a driver assigns it, and the office gets a card showing the truck it reports, when it last checked in, and any revocation asked for. Three things it is careful to say rather than imply: a binding is a claim the tablet makes about itself and nothing verifies it, so it is drawn as a claim; a revocation is a request, not a fact, until the tablet acknowledges it — in a dead spot that can be hours, and until then it is still that truck’s glass and still capturing against it; and two tablets reporting one truck is reported at the top as the finding that matters most, and it stays reported after somebody archives one of them, because archiving asks the tablet to let go and cannot make it. Archiving is attributable, like a revocation, since it does the same thing to a driver’s screen. Until the backend is deployed every tablet sees only its own row and the office view is empty on any other machine.
- NewA revenue pipeline screen: what is booked this month against what was hoped for. Quotes out, work booked, work delivered and what has actually been invoiced, on one screen, month by month, with a weighted forecast that treats a quote still open differently from one already won or lost. It refuses to state a number it cannot stand behind: a job with no agreed price behind it is listed unvalued with the reason rather than valued off an estimate, a monthly target nobody has set is not read as agreed, a run-out quote is not weighted as though the customer could still say yes, and where records exist but none could be valued the tile shows a dash, never $0.00. Nothing on it is toned as an alarm — ad hoc work is booked a day or two out, so a thin forward book is the normal shape of the business rather than a problem. It is a read-only view over records that already exist: opening it writes nothing and it needs no deploy.
- NewTraining content now has a draft, and a completion can be withdrawn. No backend deploy needed. A half-written course used to be live the moment it saved — handed to drivers on the keystroke, and a required one with nothing attached blocked that job’s departure permanently with nothing on the office side saying why. A course is now a draft until somebody publishes it, publishing refuses if a driver could not actually complete it, and Delete is gone: a course is archived, so the completions filed against it keep resolving and still name the version that was declared. A completion filed in error can now be withdrawn — the record is kept and marked, never removed, so the evidence it was ever claimed survives — and the consequence is the point rather than the flag: the driver drops back to their previous version and a gated job blocks again. The Learning screen also gains a Change log reading every collection a training record lands in, which names the ones it could not read rather than presenting a short list as a clean one.
- FixThe API token was being printed in cleartext in the deploy logs, and the comment in the file said it couldn’t be. Rotating it needs two things from Simon. Both deploy workflows handed the token to a script through a step’s
env: block on the understanding that this kept it out of the log and that a masking directive covered anything left over. Neither is true of the log: the runner writes that env: block into the step’s header before the script runs, so a mask registered by the script cannot take back a line already printed — and a repository variable, which is where the token lived, is never masked at all. The token appeared in the clear in the logs of three real backend deploys while the file asserted it could not. Both workflows now read the token from a repository secret, which the runner masks from the start of the job, and each says in its own log which source was used — because “this run printed the token” is something the person reading the run needs told, not left to infer. The two files make deliberately different calls on the old variable: the site deploy still falls back to it, since an empty token there publishes a site that cannot authenticate to its own API on every merge to master; the backend deploy drops it outright and skips its smoke test instead, because an unauthenticated call gets a 403 whether the API is healthy or broken, and a check that cannot fail is worse than no check. The same run also stops echoing half the Fleet Dynamics login. Two things are Simon’s to do and this release cannot do them: create the API_TOKEN repository secret, and rotate the token, since the old value has been in public logs. The issue stays open for both.
- NewThree more compliance reports: who was in the room, what the assessment never asked, and who could work at a client site. An attendance register across every session, worst-confirmed first, keeping “signed”, “marked present by the presenter” and “not confirmed” as three different facts — the last drawn hatched, because it is neither present nor absent and a green tick against somebody who never confirmed is a claim about attendance we cannot stand behind. The assessment analysis now names the questions never asked separately: a question nobody has been given is not a question at 0%, and folding the two together turns an untested bank into a clean result. And client-site readiness answers, for a site like BHP Newman, whether each person holds what that site requires — asked deliberately the other way round from the roster, and the screen states in full, above the table, that this is a statement about paperwork and not about who normally works there. All three are read-only views over records that already exist; no deploy needed.
v0.126.0
20 August 2026
- FixA booked renewal was hiding a registration about to expire. Odoo marks a contract that has not started yet as Incoming, and the expiry outlook was counting it as though it were in force — so a rego renewal already booked for next year masked the rego lapsing next week. The card read 0 documents expiring and the idle-asset report printed the 2027 renewal date for a truck whose registration ran out tomorrow. Silent, and in the one direction that puts an unregistered truck on the road. A contract that has not started is now counted separately as planned — still listed on the asset and marked with its start date, because excluded from a count is not the same as deleted — and it becomes live on its start date by itself, with no re-import.
- Fix…and the two counts on the Reports screen now agree, because one place decides which document is the obligation. Three screens each worked it out for themselves and two were wrong: the compliance snapshot counted every contract on file, so a truck carrying twelve years of imported annual regos reported eleven expired documents while the outlook card ten centimetres below it correctly counted the one actually outstanding. The idle-asset report had the opposite fault — it took the oldest rego on file, so a perfectly legal truck read “expired 364 days ago” on a report whose output is a decision to sell a vehicle. All three now read the same rule: the latest expiry per asset per document type, ignoring what is closed or not yet started.
- ChangeSpeed alerts can now be worked out where the data already is — but this needs a backend deploy before it does anything. Every visit to Speed Alerts, the Events screen or Fleet Overview reads back a week of the fleet’s speed samples and works through them in the browser. That was made safe in v0.123.0, but it left the page a partial check of the fleet (the busiest 120 assets) and every open still pays for the read. The recorder already has those samples in hand every minute, so it can now work out the over-limit runs itself, across the whole tracked fleet, for no extra database reads and no external lookups. Until the backend is deployed the new route does not exist, and that is deliberately safe: the app asks once, gets nothing, and every screen works out its own alerts exactly as it does today. Nothing on screen changes in this release — no page reads the new route yet, and connecting them up is the next step.
- ChangeFour automated test suites existed but were never being run, and every test count in the developer notes is now a measured number. Adding a test file does not add it to the build — each suite is named individually — so four had been sitting on disk passing nothing for months: the geofence crossing log, the filed-submission viewer, the global search box and the run-sheet reference material. All four are now run on every change, and the sweep that finds the next one is written down. A fifth was genuinely broken (a stale test, not a broken screen — the asset page grew tabs and the test was reading a hidden panel); it has been repaired and is now running too. Several assertion counts in the notes turned out to be estimates rather than measurements, which is how this project has made most of its expensive mistakes, so all of them were re-counted by running the suite.
v0.125.0
19 August 2026
- NewToolbox talks and VOCs are now a record you can hand over — who was in the room, who signed, and who signed it off. The Learning screen gains Sessions & attendance: open a session (a toolbox talk, a verification of competency, or classroom training), build the roll as people arrive, and have each person confirm their own attendance — drivers sign on their phone from Sessions I was at, or the presenter marks the roll on a shared tablet. The two are shown differently, because a signature the driver drew and a box the presenter ticked are not the same evidence. The record then carries an assessor sign-off, and that is the point: in WA mining, competency is observed, not clicked — the question a client’s HSE team and DEMIRS actually ask is who was in the room, who says so, and who signed it off.
- New…and a competency only ever issues to somebody who actually signed. A VOC sign-off mints the ticket on the compliance register itself — dated the day the session was held, carrying the assessor and the re-assessment interval, and linked both ways so you can get from the ticket back to the room it was earned in. It refuses rather than inventing a record: the assessor cannot be on their own attendance roll, a session nobody has confirmed attending cannot be signed off, and nobody who did not sign gets a competency — the roll is the evidence, so an unconfirmed name simply does not receive one. Everything outstanding is listed on the record in the engine’s own words, so the screen and the rule can never disagree.
- NewA correction never erases what was declared first. Amending a session files a new version and the original survives byte for byte, with every signature carried forward — and a signed row cannot be quietly dropped from the roll. Withdrawing a record marks it withdrawn, with a reason and who did it, rather than deleting it. Attendance is captured offline like a POD: it queues on the device and syncs when signal returns, through the same queue, so a talk held in a dead spot is not lost.
- NewThe completion register now names which version of a course each person actually saw. Re-issuing a bulletin does not retrospectively make last month’s acknowledgement cover the new wording, and the register says which one it was — the question an auditor asks.
- NewAn audit evidence pack — the one artefact you hand an NHVAS auditor or a client’s HSE lead. Pick a date range and get a single bundle in five named parts: the compliance matrix, each person’s training transcript, the certificates behind them, which content version was delivered, and the change log for the window. Exported as one sectioned CSV, and the screen is drawn from the export — so what you read is what leaves the building.
- New…and it will not overstate what it holds. Every section is always present and says which of three things it is: here is the evidence, we looked and there is nothing, or we could not look. A section quietly missing from a bundle handed to a regulator reads as “there was nothing to report”, which is a false statement — and calling an outage an empty result is the same lie the other way round. The pack’s headline names anything unavailable, states how many people and requirements it covered and as at when, and flags a ticket held with no expiry recorded as currency unknown rather than counting it as current. Where a certificate is still waiting to upload it says so, because there is no document to hand over yet.
- FixThe utilisation report can no longer lock up the tab. It already stopped reading the whole fleet; the work it then did was still one long uninterrupted calculation, so on a big register the page could sit unresponsive — and a frozen tab is not merely slow, it is one that cannot process the click you make to escape it. The calculation is now broken into slices that hand control back to the browser between them, so the page stays responsive and leaving the screen cancels the work rather than finishing it for nobody. A part-finished pass is never shown or kept as the answer.
- ChangeSessions need a backend deploy before they are stored. Session records are a new collection, so until the backend is deployed every session, roll and signature is held on the device only — it will look like it is working, and it will not survive a cleared browser or reach anybody else. The evidence pack and the utilisation fix are front-end changes and are live on the next site deploy.
v0.124.0
19 August 2026
- NewThe overdue tickets report now tells you who is actually driving. An expired licence or medical is a fact about paperwork; an expired ticket on somebody rostered for tomorrow’s Newman run is a decision for today, and the report could not tell you which was which — it never looked at the board at all. Every row now says driving today, driving tomorrow, no job today or tomorrow, or roster not known, worst first, so the phone calls come in the right order. Rostered leave is named on the row, because “expired, and on leave until Monday” is a different conversation. It looks two days ahead and says so — that is as far as work is booked as a job, and the report will not imply anything about later in the week.
- New…and “we cannot tell” is never dressed up as “not working”. Office staff, a driver with no line on the board and an id nobody recognises are all drawn hatched and sorted above the settled noes, rather than quietly reading as somebody who is off. Both reports state what they looked at (how many people, how many requirements, as at when) and name which empty they are — nothing tracked, nobody selected, or genuinely nothing lapsed.
- NewA training-needs screen, with a CSV you can take to an RTO. Who is missing what, grouped by requirement because that is how training is bought — four people need the same fatigue course, so that is one booking, not four. Narrow it by depot, business unit, role or client site. This is the list somebody was keeping by hand.
- FixThe utilisation report stops reading the whole fleet, and refuses rather than guessing. It narrowed its week of speed data using the daily summaries — but when those were unavailable it silently read every tracked asset instead, which is the same freeze that was fixed on Speed Alerts and only escaped notice because nobody had opened this page lately. There is now no such fall-back: with no summaries it says it could not look, names why, and offers a retry. It also keeps “we could not check” and “we checked, and nothing was recorded in that window” as two different sentences, because they are two different facts.
- Fix…and where it can only check part of the fleet, it says which part and which way the numbers lean. It now reads the least active assets first — the ones this page exists to find — up to a stated limit, and tells you the busiest ones fell off the end, so the averages read low rather than looking like the whole fleet. The totals are labelled average of those measured and km measured, not “fleet average”. An old, unreachable copy of the Assets hub that did the same expensive thing has been removed rather than left sitting there.
- FixEvery map now degrades honestly instead of taking the screen down with it. The mapping library comes from a public CDN, so on a depot network with no general egress, behind a proxy, or during an outage the Dashboard, Live Fleet, the geofence board, an asset’s history and both incident views showed “Couldn’t load this screen” — the whole page, not just the map. The map area now explains what is missing and offers a reload, and everything else on the page keeps working: Live Fleet lists each truck’s position as a link you can open in any map, and the asset page’s time-moving and distance figures — numbers, not a picture — now appear whether the map draws or not. The customer portal does the same on its tracking map.
- Fix…and after one good load the library is kept on the device. The driver app already did this; the two apps that most need it — the depot wall display and the tracking link a customer opens — did not. It caches the map library and nothing else, so nothing about the apps themselves can go stale. Basemap tiles are still fetched live; a map with no tiles still draws your trucks.
v0.123.0
18 August 2026
- FixTwo schedulers can work the board at once without losing each other’s changes. Until now the whole board was saved as one lump, last save wins — so if Lee moved a trailer in Perth while Rose moved a job in Karratha, whichever autosave landed second silently threw the other away. No lock, no warning, nothing on screen. The board now saves only the runs and lanes that actually changed, so two schedulers on different depots never touch the same record. This is the SharePoint failure Northfleet is replacing — “things get lost and we shut down” — and it needed fixing before a dozen people share the board.
- Fix…and if somebody does change the same run, you are told. A banner names the run, which fields changed, who touched it last and when, says plainly that your change was kept, and offers a Reload the board button. It never reloads by itself — the board changing under someone mid-drag is how it appears to have a mind of its own. Drivers see “Saved · also changed by the office” on their sync pill.
- FixSpeed Alerts no longer freezes the tab. Opening the page could lock Chrome up entirely (“Page Unresponsive”) because it worked through a week of speed samples for the whole fleet in one go. The work is now done in small slices, so the longest pause is a few hundredths of a second instead of the whole page. It also stops quietly reading the entire fleet when the daily summaries are unavailable: it says it could not check, rather than reading megabytes and hanging — and it names how many assets it skipped and where their speeds can still be seen.
- FixThe Events screen and the Movement report got the same treatment. Opening Events straight after Speed Alerts now costs no extra data at all (it reuses the same answer), and the Movement report no longer asks the database for records that cannot exist — filter it to buses, which are not tracked live, and it says “Not tracked live” and where to change that, instead of a blank result reading as though the buses never moved.
- NewPer-asset utilisation on the schedule. “We’re going to know how many jobs TR104 did this year, we paid this much for it, it did this much work.” A fold on the board lists a whole pool worst-first, so the trailers nobody is using are at the top. Where the board does not cover the window it says the figure is unknown rather than showing 0% — and “no run names this trailer at all” is kept separate from “it sat idle”, because those are different phone calls.
- NewDepot groups fold up. At forty-plus drivers the board was “quite big and clunky”. Each depot now collapses to a single line, with a collapse-all, and the row count and idle count survive the fold so a folded group still tells you whether anyone in it is spare.
- NewMark a run as timing-critical. Line haul is managed in days, not delivery times, so the board deliberately does not police the clock — five drops on one run is a normal day, not a clash. Tick timing-critical on a run and it will warn if that unit’s hours actually overlap another job, naming the other run. It is always a warning, never a block.
- FixA scheduling warning that had never actually been visible. When you moved a run, the guard raised its warning and the confirmation message immediately overwrote it in the same slot — so the one thing it existed to tell you was never seen. Both now arrive as one message.
- FixThe portal QR codes no longer depend on the internet. The sign-in and Settings QR codes were drawn by a library fetched from a public CDN, so wherever that CDN is blocked or down the codes silently disappeared — on the screen that asks for a password. They are now generated in the page itself, with no outside request. If a code genuinely cannot be produced, the link is shown as text you can copy rather than an empty square.
- NewThe sidebar behaves as an accordion. Opening one section closes the others, so the menu stops growing past the bottom of the screen. Whichever section holds the page you are on is always open — including when you arrive from a link.
v0.122.1
17 August 2026
- NewThe rig is on the per-leg con note too. That is the sheet a driver is actually handed for their leg, so it is where “what am I pulling” gets asked with the page in hand — it was the last surface still showing the prime mover alone. On a relay each leg names its own rig, because every leg is its own job and the trailers can change at a changeover even though the freight does not. Still nothing on the client copy.
v0.122.0
17 August 2026
- FixThe schedule’s conflict panel could not see a road train. A run’s trailers and dollies are set on the job, because a driver’s row carries one default trailer and a triple road train is three trailers and two dollies. The panel was still reading the row — so the same trailer could be put on two road trains on the same day with the panel above the board reporting “No scheduling conflicts”, and a dolly could never be flagged at all, because nothing looked at dollies. Both are now checked, and the panel asks the scheduler’s own allocation engine rather than working it out a second way, so the board and the panel cannot disagree.
- Fix…and it was offering an already-hooked-up trailer as the spare. When the panel flags a clash it suggests what is free to swap in, and that list was built from the drivers’ rows only — so a trailer sitting in the middle of somebody’s road train was offered as available. Free trailers and dollies now come from the same pools the scheduler drags from, and a dolly is no longer listed as a spare trailer. A driver doing five drops on one run with one trailer is still not a clash — that is a normal day, and reporting it would make the panel unreadable.
- NewThe rig now reaches the driver. The run sheet and the in-cab Drive screen name what is hooked up behind the truck — TR‑701 + TR‑702 + TR‑703 · DL‑801 + DL‑802, counted as 3 trailers + 2 dollies. Dispatch could allocate a whole rig and none of it left the board, so the one person who walks around the unit before departure could not read it on any screen we give him. A rigid pulling nothing shows nothing, deliberately.
- New…and the paperwork. The rig is on the office’s own view of a con note and on the internal con note, so whoever takes the customer’s call can say what is under the load without opening the schedule. It is not on the client copy — the same call already made about the driver, the price and the leg structure. On a relay each leg is named separately, since every leg is its own job with its own rig.
v0.121.1
16 August 2026
- FixThe “Getting started” strip had the con note in the wrong place — it listed Produce the connote at step 5, after the POD had already been captured. A quote, its booking and its con note are one record with one number (Q‑1042 → B‑1042 → C‑1042), so the con note is produced when the job is booked: it is the document that travels with the freight and gets signed at the far end, and a POD cannot be captured against one that does not exist yet. The strip now reads quote → record PO & book → produce the connote → schedule to a driver → track & capture POD → review performance, which is what the guided tour has said all along.
v0.121.0
15 August 2026
- NewAdd, correct and retire records by hand — assets, drivers, clients and vehicles. Until now every one of them arrived either built into the app or imported from Fleet Dynamics and Odoo, so a new driver, a client won last week, or an asset the import doesn’t carry had nowhere to live, nothing could be corrected, and nobody who left could be taken off the list. + New driver is on the Drivers screen, + New client on Clients, + Add asset on the asset register, and the fleet list sits on Settings beside the depots.
- NewArchive, never delete. Retiring a record takes it out of every picker, out of the scheduler’s pools and — for an asset — out of the live GPS sweep, so it stops spending one of the limited tracking slots. Everything already raised against it is untouched and still reads correctly: a driver’s jobs, checks and tickets, a client’s con notes and invoices, an asset’s service history and recorded trips. Before you confirm, the screen tells you exactly what points at the record and how much of it is still open — “3 jobs, 1 still open” — and it is a warning, not a block. Anything archived can be restored, and archived rows are shown on request rather than being hidden for good.
- NewAn ID is never re-issued. If driver D21 is archived, the next driver is D22 — never D21 again, and typing it in by hand is refused with the reason. Re-using it would silently re-attach the departed driver’s jobs, checks and licence records to a different person, and nothing on screen would show it. For the same reason an asset’s unit ID is locked once set: its recorded position history and service records are filed under it. The plate stays editable, since on the live register that field doubles as a status note.
- FixClients, drivers and vehicles were never being saved. None of the three were included in the document the app stores, so they existed only for as long as a browser tab was open. Nothing had ever written to them, so it had never shown — but it meant that without this fix every record added on the new screens would have vanished on the next reload. All three now save, and merge properly when two people are working at once: a record added on one machine survives a sync from another that has never seen it.
- FixAdding a vehicle broke the offline demo map. The simulated GPS built its list of vehicles once when the page loaded, so anything added afterwards had no position and stopped the whole demo feed. Archived vehicles are now also left off the live map, matching how an archived asset behaves on the real feed.
- NoteNeeds a backend deploy. Clients, drivers and vehicles are new to the saved document, so until the backend is redeployed they are kept on the device and will not follow you to another machine. Everything else — adding, editing, archiving, restoring — works now.
v0.120.0
15 August 2026
- NewWhat’s available today, at the top of the schedule — drivers, trucks, trailers and dollies are now four collapsible sections, closed by default, so the board starts on the board. Each header carries the number free without opening it (Trailers — 24 of 24 free), so the whole point — seeing what you have to work with — is answered at a glance. Open one to see the individual units and drag them onto a run; it remembers which sections you left open.
An empty pool says “none on register” rather than “0 free”, because a pool nobody has entered and a genuine shortage are different problems — and a pool that is genuinely short is marked in red. A pool that could not be read gets no fold at all and says so, since “we couldn’t tell” hidden behind a closed section is indistinguishable from “there are none”. Each header also names where its numbers came from — the asset register or the sample fleet list — because the two give very different totals and a count without that reads as the whole business either way.
- FixPool headings showed the internal name — every card was titled “trailer” rather than “Trailers”.
v0.119.0
14 August 2026
- NewDrag a truck, trailer or dolly out of the pool straight onto a run — and hand it back with the × on the run. This is what replaces typing an NF number next to a driver’s name and deleting it again when the rig changes. A run shows exactly what it is pulling, so a triple road train reads as three trailers and two dollies on that job rather than as one default trailer against the whole row. The moment an asset is on a job it leaves the free pool for that day, so it cannot be dragged onto a second run — there is nothing left to drag.
Dropping a prime mover swaps the truck from that day onward, which is how trucks actually move: they stay with a driver until something breaks down. Driver chips are deliberately not draggable — a row on this board is a driver, so giving a run to somebody else means dragging the run onto their row, which already worked. Offering two contradictory ways to do the same thing would make the board worse, so the rail says which one it is.
Every drop goes through the same guard as moving a run: rostered leave or a workshop day is refused outright, the same unit twice in one rig is refused, and anything else — including the same trailer on another job that day — is a warning that names the other job, because at day level nobody can say whether two runs actually overlap. A cell with no job behind it (a preload, a return to base) says it cannot carry a rig instead of appearing to accept one.
v0.118.0
14 August 2026
- NewRates in the back — a quote is priced from the rate card, and that price carries to the invoice — agreed rates per client and per lane, service tiers, and a Rates screen to maintain them. Building a quote now proposes charges off the card instead of off somebody’s memory, every line says which rate it came from so it can be defended to a customer, and any line can be overridden by hand — an override is shown as an override, never quietly mixed in with a calculated figure. When the customer accepts, the accepted price is stamped on the job and the invoice is built from it rather than re-derived, so what we bill is what they agreed to.
- NewA charge we have no rate for is not priced at zero — it is listed as not priced, contributes nothing to the total, and the quote says it is incomplete. Understating a quote is how you win work at a loss, and silently dropping a line is worse than admitting we could not price it. A rate deliberately set to 0 — a waived charge, a nil pilot fee — is still a real answer and is kept as one; clearing a rate box removes the rate rather than storing zero.
- FixInvoices were being built from a flat four-hour assumption instead of the lane rate — where a job had no quote behind it, the invoice billed 4 hours at whichever hourly rate happened to be first in the origin depot’s card. On the sample board that priced Perth → Port Hedland at $768 against a lane rate of $18,158, and it was the source for every invoice on the board. Nine of the ten now price off the rate card; the tenth is local work with no captured times, and it shows a dash and says plainly that the invoice is not yet the amount to bill.
- FixA quote for a depot with no rate card was priced off Perth’s — recommended charges fell back to the Hazelmere card for any depot without its own, so a Tom Price or Kalgoorlie job was quoted at Perth metro rates with nothing on screen saying so. Such a depot now reads as not priced.
- FixAn unpriced line showed the customer “$0” on their invoice in the portal, which reads as a charge waived rather than a charge not yet worked out. It now says “not yet priced”.
- NoteThe seeded rates are prototype figures, not Northfleet’s rate schedule, and the hot-shot and direct-drive uplifts are sample percentages — labelled as such on screen. There is no rate history yet, so “what was this lane on 1 July” is not answerable. The rate book needs a backend deploy before it persists.
v0.117.0
14 August 2026
- NewA customer can accept a quote from a link, and give their PO on the way through — the quote screen issues a long random link you can email. The customer opens it, sees the quote, types their name and position, enters their PO or reference and confirms they have authority; that creates the booking, and the same job carries the same digits onward (Q‑10042 becomes B‑10042). Their reference is checked against whatever that client requires — a Coates Load ID, a Water Corp job number — so it can’t be accepted without the thing invoicing will need.
Re-opening the link after acceptance shows what was accepted, when and by whom. It cannot be accepted twice and cannot create a second booking. A quote that has expired, been cancelled or been lost says so instead of accepting.
What the link is, stated on the page rather than implied: it is a long random code, so it is not guessable and it covers that one quote only — but it is not a sign-in. Anyone holding the link can use it, and nothing checks who they are. No signature is captured: the record is the typed name, position, authority tick and timestamp, and the page says exactly that and offers a phone call for anyone who needs signed paperwork. A drawn signature would have looked like stronger evidence while being worth no more.
Recording a customer’s reply yourself still works as before, and the two are recorded as different things so conversion reporting can tell a link acceptance from an office one.
- NoteThe acceptance link is not a signed, expiring, single-use token — that needs server-side work and has not been built. Nothing in the app suggests otherwise.
v0.116.0
14 August 2026
- NewA Drivers screen — the record behind the scheduler’s driver pool — who can drive what, whether the ticket behind it is still current, whether they have work today, and whether today’s fitness-for-work record has been filed. Filterable by depot, by “needs a look” and by “no work today”, with a page per driver.
The distinction it exists for: a qualification recorded against a driver and a current ticket behind it are two different things. A driver can be marked as rated for a hundred-tonne float while the ticket expired last month, and the chip colour is the ticket’s real status, not the claim. Where a ticket is held but nobody has recorded an expiry, it is drawn hatched and says currency cannot be confirmed — never green, because telling a scheduler somebody is current when nobody knows is the one mistake here with a licence consequence. Nothing on file reads as a gap in the register, not as a driver who holds nothing.
Availability is read from the schedule, which stays the one place it is set — there is deliberately no second copy here to fall out of step. A day with only a start time on it reads as yard duties, not work; a rostered fatigue day is not flagged, because it is planned.
Everything on the screen is an advisory: it is a reason for a scheduler to look, never a block. It leads with names and numbers rather than a compliance percentage, because “94% compliant” hides the one driver who can’t legally do tomorrow’s Newman run.
v0.115.0
14 August 2026
- NewAn address book — every gate, yard and branch, with the people at each one — searchable, filterable by client and depot, with contacts you can add and confirm. Locations are archived, never deleted, because a con note keeps a copy of the address it was booked against and somebody may have to say later where that address came from. A contact’s currency is shown as three different things, not two: confirmed and current, confirmed but old, and never confirmed at all — that last one is drawn hatched rather than green, because a green tick on a number nobody has ever checked is what puts a driver at a mine gate ringing a dead line. There is a worklist of contacts needing a call, split the same way, so “nobody has ever checked this” is never mixed in with “this went stale”.
- NewA con note now keeps a copy of the address and contact it was booked with — so correcting the address book afterwards cannot rewrite a con note already sent. Where the book has moved on since, the sheet says so rather than quietly showing today’s version.
- NewThe con note comes in two versions — ours and the client’s — the internal sheet carries what our people need, and the client copy carries no price, no driver name, no internal contact and none of the leg structure. Today that is one sheet printed three times and crossed out by hand.
- FixBooking a job no longer pre-fills the last contact you used — re-opening a job restored the previous choice, which is exactly the “we’ve already got a name and a number, so nobody changes it” habit the address book exists to break.
- FixChoosing a location no longer wipes special instructions you were part-way through typing for the other end of the job.
v0.114.0
14 August 2026
- NewThe schedule board is now the engine room — pools, and a guard against booking the same gear twice — the board shows what is free in each pool (drivers, trucks, trailers and dollies) for the day, and says whether those numbers came from the asset register or the sample list, because a count without that reads as the whole business either way. Driver qualifications are back on the row — the column that went missing — so you can see at a glance who can take a hundred-tonne float; where nothing is on file it says “no tickets on file” rather than showing a driver who holds none. Rows are grouped in depot order with projects and general cranes at the top, and the projects group says plainly that it is managed outside this board and why it is shown anyway: the two divisions share drivers, so somebody must not be committed twice. What a truck is pulling now reads off the run by code — TR, DD (drop deck), FT (flat top), F100 (100 t float), DL (dolly) — and moving a run now moves its trailers and dollies with it, so gear can’t look free on the new day and committed on the old one. Allocating something on rostered leave or a workshop day is refused and says why; the same trailer twice in one rig is refused. Anything else — the same driver or trailer appearing on another job that day — is flagged with the other job named rather than blocked, because a driver doing two or three drops in a day is normal and times aren’t recorded, so “go and look” is the honest answer. Taking a Perth trailer for a Karratha job is never blocked — tying depots together is where the money is.
- NewAn idle driver is now obvious at a glance — the morning scan down the board. A driver with nothing on today is marked, and each group says how many that is or that everyone is working. The distinction that matters: a cell reading only “7am” is yard duties, not work — come in, we’ll find clean trailers and do something — so it is flagged rather than counted as covered, which is exactly the row you open the board to find. A rostered fatigue day is not flagged, because it is planned and flagging it would bury the real gaps.
- NewA quote, its booking and its con note now read as one job on screen — the quote shows the whole thread: the same digits at every stage (Q-1042 → B-1042 → C-1042), where it is now, the customer’s PO, and who moved it and when. A job that needs a PO and hasn’t got one says so, and says that it blocks invoicing, rather than being quietly invoiced without one. Cancelling goes through the permission check and states plainly that the name recorded is not verified, because there is no sign-in yet — a permission check that presents itself as security is worse than none. Cancelling a con note without an approver recorded still works but says an approver is missing, and records that gap on the job.
- NewQuote conversion — what share of quotes we actually win — on the quotes list: how many were quoted, won, lost, expired and still open. The rate is over quotes raised and says so, with a note on how far it can still move while quotes are open. With nothing raised there is no percentage at all rather than 0%, which would read as a week nobody won anything in.
v0.113.0
14 August 2026
- NewA quote, a booking and a con note are now one job with one number — today the same job is keyed in at quote, again at booking and again at con note, and nothing ties the three together, so nobody can say what share of quotes we actually win. A job is now one record from quote through to invoice, carrying the same digits at every stage — Q-10042 becomes B-10042 becomes C-10042 — so a con note can tell you what it was quoted as, and quote conversion is a number we hold rather than one somebody estimates. Accepting a quote captures the PO, and a job that needs one and hasn’t got one is flagged rather than quietly invoiced. Cancelling a con note is permissioned and every state change is stamped with who did it and when — and because there is no sign-on yet, the screen says so instead of implying the name it recorded was verified. Conversion reporting shows no rate at all until there are quotes to divide by, rather than 0%.
- NewAsset pools — drivers, trucks, trailers and dollies, and a guard against booking one twice — a job is built by taking a driver, a prime mover, trailers and dollies out of a pool, and they go back to the pool when it’s done. Dollies were tracked nowhere before: the instruction was “go out and grab a couple” and then hope there were enough. Allocating something that is already on another job that day is now blocked at the moment of allocation, and the clash names the other job — rather than being found later, or not at all. Leave and workshop days block too. Taking a Perth trailer for a Karratha job is only a warning, never a block, because tying depots together is where the margin is. Trailers and dollies carry type codes — TR, DD (drop deck), FT (flat top), F100 (100 t float), DL (dolly) — so what a truck is pulling is legible at a glance. Per-asset utilisation answers “how many jobs did TR104 do”, and refuses to put a percentage on a window the board doesn’t cover.
- NewDriver qualifications are checked against the job, not remembered — MC, road train, 100 t float and the rest now sit against the driver and are checked when allocating, reading from the compliance register where a ticket has been filed. Where nothing is on file it says “not known” rather than treating an empty record as a pass.
- NewA relay driver gets a con note for their own leg — on a multi-leg job each leg now has its own con note, its own pickup and drop, and its own load check, while the price stays on the job so nothing is invoiced twice. A driver sees their leg and not the whole journey. Re-homing a load onto a different trailer mid-chain is recorded rather than lost.
- NewAn address book with contacts, and a con note that keeps a copy of what it was told — every gate, yard and branch we deliver to, with the people at each one. A contact nobody has confirmed for six months is flagged for checking, and “never confirmed” is shown as its own state rather than as fresh. A con note takes a snapshot of the address and contact it was booked against, so correcting the address book later cannot rewrite a con note already sent. Locations are archived, never deleted.
- NewIn-cab tablet — one device per truck, and the driver signs on to it — the device knows which truck it is in, so the run sheet, the truck tab and an incident report all name the right vehicle without anybody choosing it. A driver signs on at the start of a shift and off at the end, and the shift clock runs from sign-on rather than from when the app was opened — a tablet left powered through a handover would otherwise charge the incoming driver with the outgoing driver’s hours. Signing off with work that hasn’t reached the office stops, names what is outstanding and offers to send it again; there is deliberately no way to discard it, and the warning follows through to the next driver, who is sitting in front of the only device that has it. Fatigue is on glass — a green/amber/red bar on the run screen and on the Drive display, with every figure and every word coming from the work-diary adapter rather than a second copy of the thresholds. A phone is unchanged: no truck, no sign-on, exactly as before.
- NewCustomers can get their own PODs and invoices — a customer wanting a delivery record rings up today and somebody finds it, prints it, scans it and emails it. The portal now has a My documents area listing that customer’s own delivery records and invoices, newest first, searchable by their reference — their PO, a Coates Load ID, a Water Corp job number — as well as by ours, with a printable record behind each. Switched on per client from the client’s agreement terms and off for everybody until somebody turns it on: a client nobody has enabled sees the portal exactly as it is today. A customer can only ever reach their own documents, and asking for somebody else’s by guessing the URL gives the same answer as asking for one that doesn’t exist, so the address bar can’t be used to find out whose connote numbers are whose.
- FixSaving a client’s agreement terms no longer wipes settings that form doesn’t show — it rewrote the whole record, so saving a fuel levy would have silently switched that client’s portal document access back off. It now keeps anything it isn’t editing.
- NoteThe job thread, the address book and driver qualifications need a backend deploy before they persist. Until then they work in the browser and are cached locally, but are not saved to the database.
v0.112.0
14 August 2026
- FixAn out-of-date licence or ticket now actually stops a departure — the compliance gate was showing the problem on the dispatcher’s consignment and on the driver’s Tickets tab, but nothing was checking it at the moment a driver taps Departed pickup, so a driver whose ticket had expired was never actually stopped. It now blocks that departure and names the reason — and it still says “no record on file” where there is none rather than claiming something expired. A safety control that displays but doesn’t enforce is worse than none, because the screen says it is working.
- NewAssessments — a short check on the end of a course, and a report on what everybody gets wrong — a course can now carry questions, and the driver has to pass them rather than tap “mark complete”. Deliberately small: this is for the handful of things we write ourselves (a haul-road bulletin, a toolbox talk), not for the licences and site inductions that come from an RTO or the client — those live on the Compliance register. There is no proctoring and no anti-cheat, because this is a supervised workforce and that would be theatre. Four question types (single choice, multiple answers, true/false, short answer), a pass mark, an attempt limit, an optional draw of N questions from a larger bank (so the same paper isn’t going round camp) and shuffled answer options. The rule that matters: a fail is not a completion — it files the attempt as part of the training record but files nothing that says the course is done, so a job gated on that course stays blocked. “Hasn’t sat it”, “sat it and didn’t pass” and “out of attempts” are shown as three different things, on the driver’s screen and on the consignment, because they need three different phone calls. A driver who fails sees which questions they got wrong (with whatever explanation the author wrote), what to do about it, and how many goes are left; when the goes run out it says so and offers a one-tap call rather than another attempt. Every attempt is kept, passes and fails alike. New Assessment analysis tab on the Learning screen: per question, how often it was asked, how often it was got wrong and the failure rate, worst first — which finds both badly-written questions and real gaps in what people know, and says on screen that it can’t tell you which. Exports to CSV. With nothing sat yet it says “no attempts recorded yet” rather than a 0% failure rate, which would read as “everybody passes”. Editing an assessment re-issues the course (so completions stay tied to the version actually taken, and the attempt allowance resets), and what the old version said is now archived rather than overwritten. A course that has been opened and not finished finally shows as In progress instead of untouched. Attempt records need a backend deploy before they persist.
v0.111.1
13 August 2026
- Fix“‹ Learning” now takes you back out of a course — while editing a course, the back link did nothing, so the only way out of the editor was Cancel. The course editor isn’t a separate page — it opens over the Learning screen — and the link was asking the browser to go to the page it was already on, which does nothing at all. It now closes the editor and returns to the course list, and it works with the keyboard. A front-end change, live on the next site deploy.
v0.111.0
13 August 2026
- NewCompliance register — who holds what, what expires when, and what that blocks — a new Compliance screen answering the question the training courses never could: not “did somebody click through a course” but “is this driver actually allowed to do tomorrow’s job”. Most real training isn’t ours — fatigue, load restraint, high-risk work licences, medicals and client site inductions come from an RTO or the client — so the register records the thing that matters: a dated, verified, expiring certificate against a person. It keeps eight distinct states rather than a compliant/not-compliant flag, because “no record”, “expired”, “awaiting verification”, “in grace” and “waived” need five different actions. A certificate a driver uploads counts for nothing until somebody verifies it, and you cannot verify your own — the register refuses it by name. Includes a person × requirement matrix (filterable by depot, business unit and role) that leads with the names of who is blocked rather than a compliance percentage, an expiring/overdue view on 30/60/90-day horizons, a verify queue, a waiver register where every waiver carries a reason, an approver and an expiry, and a per-person training record that states for every requirement why it applies and what evidence sits behind it — the artefact you hand an auditor. Everything exports to CSV matching what’s on screen. A missing or expired gated requirement now shows a Compliance gate on the consignment naming exactly what’s wrong — and it says “no record” where there is none rather than claiming something expired. Where currency cannot be confirmed it says so in its own right instead of showing a reassuring green tick. Renewal dates now land on the real anniversary (the old month arithmetic drifted by a day or two, and a month from the 31st landed in the wrong month). Sign-in isn’t built yet, so the acting user is a selection rather than a verified identity — the screen says so, and every action is recorded in the change log. Persistence needs a backend deploy.
v0.110.1
9 August 2026
- Fix“What to look at” panel now lays out correctly — the recommendations panel shared a style name with the quote rate-card rows, which made it render sideways (heading squeezed into a narrow column, cards pushed to one side). The panel now uses its own style namespace and stacks properly: heading, then the cards in a clean vertical list. A front-end change, live on the next site deploy.
v0.110.0
9 August 2026
- New“What to look at” on the Assistant page — the Assistant screen now opens with a proactive recommendations panel: a ranked list of what actually needs a dispatcher’s attention right now, built only from records the app already holds — speed exceedances, loads held by an L&D non-conformance, prestart defects, expiring vehicle documents, geofence alerts, relay-chain problems, client-rule breaches, demurrage, wet-hire opportunities and register data gaps. Each card names the finding with a count, a one-line detail, the evidence behind it and an “as of” time, and links straight to the screen to act on it. It is deterministic and never invents — clean data shows an honest “nothing needs your attention right now”, and a card measured against indicative data (a posted road limit, a wet-hire trip that might combine) says so. Findings are collapsed to one card per kind so nothing is repeated, sorted safety-first, and the busiest few are shown with the rest counted. You can dismiss or snooze a card, and — where the assistant is connected — ask the assistant to explain any card in plain English (a run reassignment comes back as a confirm-first proposal, never an automatic change). The panel works even offline (it reads records, not the API) and never blocks the chat. A front-end change, live on the next site deploy.
v0.109.1
9 August 2026
- FixThe assistant can no longer show a configuration detail in an error — a connection error now shows a plain “something went wrong” message and keeps the technical detail on the server, and the assistant refuses to run at all if its API credential has been stored incorrectly (returning the normal “not configured” state) rather than passing a malformed value through and surfacing it. If you saw a long error on the Assistant page, rotate the assistant’s API key and re-store it, then re-deploy the backend to pick up this fix. A backend change.
v0.109.0
8 August 2026
- NewThe assistant can now propose an action — and you confirm it — ask the assistant to reassign a run (“move CN-1042 to Sam on Monday”) and it replies with a proposal card rather than making the change: it shows the run, the from → to driver, the day, any warnings, and the record lookups it was based on, with Confirm and Cancel buttons. The assistant never writes — nothing changes until you click Confirm, and the change is then made through FleetView’s normal save path so it lands on the dispatch board, the driver’s run sheet and the change log exactly like a hand-made move. Confirm re-checks against the live schedule at the moment you click — if the run has moved, been reassigned by someone else, or the new driver is now on leave or a rest day, it refuses and asks you to try again rather than writing a stale change. Cancel discards it and writes nothing. An honesty note states that access control isn’t enforced yet (pending sign-in), so actions run as the current session and are recorded in the change log. Because this is the first path where the assistant can change live data and there is no verified identity yet, the write capability ships switched off and is turned on deliberately via the proposals input on the backend deploy — until then the assistant stays read-only. A front-end change over the assistant API; live on the next site deploy.
v0.108.0
8 August 2026
- NewAsk the fleet a question — the in-app assistant — a new Assistant screen lets you ask about the fleet in plain English (“where is NF-104?”, “which trucks are over the limit today?”, “what’s booked for BHP tomorrow?”) and get a written answer. It is grounded: every answer is built from record lookups only, and each one shows which tools ran and which records it cited, so you can see the answer is backed by the data rather than guessed. It is read-only for now — it looks things up and never changes anything (acting on a suggestion comes later). Honest by design: positions are stated as last-known, not live, live tracking covers only the asset types set to track, and a question that runs long returns a clearly-marked partial answer rather than a broken one. It needs the deployed FleetView API; on a local-only build the screen says so instead of pretending to work, and if the service is unavailable or busy it shows a clear message rather than an error. A front-end change over the assistant API deployed earlier; live on the next site deploy.
v0.107.0
8 August 2026
- NewChange Log — the audit trail is now viewable — a new Change Log screen shows the before/after history the change-log capture has been recording: for each save it lists what changed (record + collection), when, which operation (create / update / delete), who (marked unverified until sign-in lands), and a field-level before → after. Filter by record, user, date range or operation; page through; and export the current view to CSV. It reads through a new paged, filtered
GET /audit API. Honest by design: an on-screen note states the log is of net persisted changes (not keystrokes), identities are unverified until SSO, and — with sign-in/roles not built yet (#66) — the screen is visible to anyone with dispatcher access for now. Needs a backend deploy to serve the data; until then the screen says so rather than showing nothing.
v0.106.0
8 August 2026
- NewAsset operational status — each asset can now carry a settable operational status — available, on hire, internal use only, spare, awaiting service, needs repair, out of service or sold / disposed. Set it on the asset register per row or over a selection (just like business unit), filter the register by it, and it shows as a colour-coded badge on the asset page and as a Status column on the Lost Revenue report — so an idle asset that’s “on hire” or “needs repair” reads differently from one that’s genuinely “available”. Set by hand (nothing in the tracking or Odoo feeds carries it), left blank until you say so, and it survives Fleet Dynamics and Odoo re-imports. A front-end change, live on the next site deploy.
- NewChange log — groundwork — the first piece of an audit trail: every save to the database now records a server-side before/after change record (which record, what changed, when, and the best-available “who”). It’s captured at the one chokepoint every write passes through, stored where it can’t be purged, and is entirely defensive — it can never slow or block a save. No screen yet — the viewer and read API are later steps; the identity is marked unverified until sign-in (SSO) lands. Needs a backend deploy to start recording.
- FixDelete-confirmation dialogs no longer hide behind the map — confirming a geofence delete (and any confirmation opened over a map) drew underneath the map, so the Cancel/Delete buttons were unreachable. Dialogs now sit above the map everywhere. The geofence list is also now sorted alphabetically (natural order, so “Newman 2” comes before “Newman 10”). A front-end change, live on the next site deploy.
- FixLearning: a course can no longer be saved with no content — a course set to a content type (video / SCORM / document) but with nothing actually attached used to save silently, only surfacing to the driver as “No … is attached”. It’s now caught at authoring — the save is blocked with a clear message, and the Learning list flags any content-less course. A front-end change, live on the next site deploy.
v0.105.0
6 August 2026
- NewTelematics screen — all the GPSWOX data in one place — a new Telematics screen (under Assets) lists every GPSWOX-tracked device in one view: its live/offline state and “last seen”, position (tap to open the map), the onboard sensors (ignition, seatbelt, real odometer, fuel, engine hours, driver-monitoring and more), and which register asset it’s linked to. A monitoring view of the whole tracked fleet, separate from the per-asset panels — both share the same rendering, so they always agree.
- NewLink GPSWOX devices to your assets — GPSWOX covers a subset of the fleet, and a device’s telematics only appear on an asset once the two are linked. A new Link GPSWOX devices step on the asset register (and on the Telematics screen) lists the devices that don’t yet match a register row and lets you attach each to the right asset in a couple of clicks — matched by hardware id, never guessed, and the link is a hand-made mapping that survives Fleet Dynamics and Odoo re-imports. Link a device and its asset page’s From GPSWOX panel lights up immediately. A front-end change, live on the next site deploy.
v0.104.0
6 August 2026
- NewGPSWOX live telematics on the asset page — for the assets tracked on GPSWOX, their page now carries a From GPSWOX panel showing the onboard telematics: ignition on/off, driver seatbelt, the real odometer read from the vehicle’s own computer, fuel level (percent and litres), engine hours, battery voltage, and any other sensors the unit reports — each with an “as at” timestamp and a stale flag when the tracker has gone quiet. A sensor the model doesn’t have reads “not reported”, never a misleading zero or off. The real odometer becomes the truest source for that asset’s service-due countdown, named on screen. And on Live Fleet, where GPSWOX has the fresher fix for an asset it covers, the map uses it and says so — both feeds pass the same staleness gate, so a dead tracker’s last-known position is never shown as live. Only the GPSWOX-tracked subset is affected; every other asset behaves exactly as before. Completes the GPSWOX integration (epic #197). Needs a backend deploy to activate the live feed; until then the panel is simply absent.
v0.103.0
6 August 2026
- NewGPSWOX tracking — groundwork — first foundations for integrating GPSWOX, a second vehicle-tracking platform that holds richer data (fuel, ignition, odometer, engine hours, driver ID and more) on a subset of the fleet. This release lays the plumbing only: secure credential wiring, a backend adapter that polls the whole fleet in one call and degrades silently if the service is down, a staleness gate so a tracker that stopped transmitting is never read as a moving truck, and device-to-register matching by hardware id (unmatched devices are reported, never guessed). The host was confirmed to serve HTTPS, so the access token is never sent in the clear. No user-visible change yet — the richer data surfaces in a later release; backend routes need a deploy to activate.
v0.102.0
6 August 2026
- NewRoute & run reference material — you can now attach reference documents — a route plan, a map, site notes, a PDF or photo, or a hosted video — to a route corridor (so every run on that origin→destination inherits it, the default) or to a single run as an override. The material shows read-only on the dispatcher’s consignment panel and on the driver’s run sheet and in-cab Drive screen, one tap to open. It is deliberately not a training course — no completion, no version, no gate, just there to open. Files upload to media storage when the backend is deployed, or you can paste a link; until then it saves locally, like every other record. A front-end change with a one-line backend whitelist addition; media persists once the backend is deployed.
- NewGeofence webhook alerts — a geofence can now POST its enter / exit / crossing events to an external webhook URL, on top of (or instead of) the Events log — configured per fence in the geofence editor. It is a best-effort notification fired from the browser (the Events log stays the source of truth), debounced by the same boundary hysteresis so you get one alert per crossing. Email and SMS routing are a later increment (they need a backend sender). A front-end change, live on the next site deploy.
- FixDeploy logs no longer print the API token — the site-deploy workflow used to substitute the API token inline into its build script, so the value could appear in the CI logs. The token is now passed through the environment and masked, and the log shows only whether it is set. A CI / security change; no effect on the running site.
- FixDeleted geofences are tidied up over time — a follow-on to the geofence save fix: a deleted fence leaves a small “tombstone” marker so the deletion propagates and can’t be undone by a stale device. Those markers are now garbage-collected after 90 days — far beyond any realistic device-offline gap — so they can’t accumulate forever. An active fence, and any marker too old to be dated, are never touched. A front-end change, live on the next site deploy.
v0.101.0
5 August 2026
- NewLost Revenue report restyle — traffic-light idle bands, service & expiry columns — the idle-assets report now reads like the fleet spreadsheet: each row is colour-banded by how long the asset has been idle (green under 3 days · amber 3–7 · red 7 days+), on a tighter grid, with three new colour-coded columns pulled from the same shared derivations the asset page uses — Service (due / overdue against the odometer), Registration expiry and Insurance expiry (green OK · amber within 30 days · red expired). Every one degrades to — when nothing is on file rather than implying all-clear. A Warranty column is included too — it shows — for now and fills in automatically once warranty dates are imported from Odoo. The existing Location column (where each asset was last seen) is unchanged. A front-end change, live on the next site deploy.
v0.100.0
5 August 2026
- FixYour geofences stop disappearing — fences you drew could vanish because the app used to save the whole geofence list as a wholesale overwrite: a second tab, another device, or a maintenance job that happened to hold an older or emptier list and saved first would overwrite the fuller one, silently dropping fences. Geofences now merge by identity (each fence carries a last-edited time and the newest edit wins), so one stale copy can no longer wipe another’s work; a fence a device hasn’t heard of is kept, not deleted. Deleting a fence still works everywhere — it’s recorded as a tombstone that propagates, so a removal isn’t “undone” by a device that still had the old copy. Your three current fences are safe; the ones lost earlier were overwritten before this fix. A front-end change, live on the next site deploy — no backend change needed.
- FixThe Assets screens no longer crash the browser (“Aw, Snap”) — opening an asset’s page built a map each time and never released it when you navigated away, so a session of clicking through assets leaked one full map plus a week of GPS history per asset until the tab ran out of memory and crashed. The asset page now tears its map down on exit, the same way every other map screen already did. Heap stays flat across repeated visits. A front-end change, live on the next site deploy.
- FixHeavy report screens no longer pull the whole fleet’s history — the Fleet Overview, Utilisation report and the map’s speed-history popup each fetched position history for every tracked asset (tens of megabytes) even to fill one figure or draw one small sparkline — and a depot wall left on Fleet Overview re-pulled it every 60 seconds, eventually exhausting memory overnight. Each now fetches only the assets it actually shows (the popup fetches just its one truck; Overview and Utilisation read from the compact daily summaries), and Fleet Overview and Lost Revenue are excluded from the 60-second wall refresh. Same numbers on screen, a fraction of the data. A front-end change, live on the next site deploy.
v0.99.0
4 August 2026
- FixA parked truck can no longer show as speeding — a frozen GPS fix (the telematics unit echoing its last reading while the vehicle sits still) used to read as “· Moving” at a live speed on the map popup, the Live Fleet list and the wet-hire card — and a sustained phantom speed could even be logged as a false speeding alert, polluting the compliance log. Movement is now judged from the fix’s age and whether its position actually changed, not from the speed number alone: a stale fix reads “stale · last seen N min ago” instead of “Moving”, and a high speed on a fix that hasn’t moved is never ingested as an exceedance. A missing fix time degrades honestly (“unknown”, never falsely “stale”). A front-end change, live on the next site deploy.
- New“Last moved …” for parked assets — anywhere a stationary asset’s live state is shown — the Movement page, the tracking popup, the Live Fleet list and the asset page — now shows how long since it last moved (“last moved 40m ago”, “3d 4h ago”, “3 weeks ago”). It reaches back weeks using the kept daily summaries and refines to minutes from recent detail, through one shared calculation (the Idle-assets report now uses it too, so the two can never disagree). Honest by design: a currently moving asset gets no readout, a gap beyond the window says “not moved in Nd+” rather than inventing a number, an asset with no history reads “no movement recorded” (never “0m ago”), and a unit that is simply not reporting is kept distinct from one that is parked. A front-end change, live on the next site deploy.
v0.98.0
4 August 2026
- NewSCORM training packages — upload, host & play in-app — the Learning system now supports SCORM, the standard format for interactive e-learning (the kind of course an authoring tool like Articulate or Captivate exports). A dispatcher uploads the package’s .zip on the Learning screen; the backend unzips it, reads its manifest (both SCORM 1.2 and 2004) to find the entry page and version, and hosts it. Drivers play it inside My Learning in a sandboxed viewer, and the course records itself: when the module reports complete it files the same immutable, versioned completion record as every other course — carrying the score and the module’s resume state, so a driver who leaves part-way picks up where they left off. It slots into everything already built — audience rules, job gating, refreshers and the completion register & CSV export all work for a SCORM course unchanged. It degrades honestly: where the hosting service isn’t switched on the upload says so and you paste a URL as before, and offline it says a SCORM course needs signal (bulletins and toolbox talks still work offline). Needs a backend deploy (new hosting routes) to switch on.
v0.97.0
4 August 2026
- NewUpload training videos directly (no more pasting URLs) — the Learning authoring screen now has an Upload file button for a video or PDF. The file goes straight from the browser to S3 via a short-lived signed link (bypassing the size limits of the old base64 upload path that suits a signature but not a 200 MB video), and the course’s content link is filled in automatically. Playback streams the video direct from storage with seeking, rather than through the API. It degrades honestly: where the upload service isn’t switched on it says so and you paste a URL as before, so nothing changes until it’s deployed. Needs a backend deploy (new upload route + bucket settings) to switch on; SCORM upload is a later step.
v0.96.0
4 August 2026
- NewRefresher training now shows when it’s due to be renewed — courses with a refresh interval already re-appear as outstanding once they lapse; now the renewal date is shown before that happens. On the driver’s My Learning, a completed refresher shows “↻ Renews <date>”, highlighted “due soon” in the last 30 days. In the dispatcher’s completion register, a new Renews column shows each refresher’s renewal date (amber when due soon, red when overdue), the CSV export carries it, and a “N due for a refresh” count summarises how many drivers need to re-do a course. A front-end change, live on the next site deploy.
v0.95.0
4 August 2026
- NewA required induction can now block a job until it’s done — training courses marked required and “gate the job” now hold a departure the same way an L&D non-conformance does. If a driver hasn’t completed a course that applies to a run — say a client’s site induction — the docket shows a STOP panel naming the course, with a one-tap call to operations and a shortcut into My Learning, and the departure time simply won’t stamp until it’s complete (enforced on both the docket and the in-cab Drive screen). The gate is job-specific: a BHP site induction blocks BHP runs, not an unrelated Rio job. Dispatch sees the same hold on the consignment as a “Departure blocked” panel. A front-end change, live on the next site deploy.
v0.94.0
4 August 2026
- NewTraining completion register & export — the Learning screen now has two views: Content (authoring, as before) and a new Completion register. The register lists who has completed which course, and when, from the immutable, versioned records drivers file — filterable by course and by driver. An Export CSV button downloads the current view (e.g. everyone inducted for a client site, with dates) as an auditable spreadsheet, timestamped and Excel-ready. This is the compliance evidence the Learning system is built to produce. A front-end change, live on the next site deploy.
v0.93.0
4 August 2026
- NewDrivers can now see and complete their training — a “My Learning” tab — the driver-app half of the Learning system. A new Learning tab shows each driver exactly the courses that apply to them — worked out from the depots, clients and asset types they work — split into Overdue, To do and Completed. They complete a course the way that fits it: acknowledge a safety bulletin or toolbox talk (“I’ve read this”), watch a video to the end, or open a document. Each completion is filed as an immutable, versioned record — the audit evidence — and, like a delivery or a form, it’s saved offline and syncs when signal returns. Bulletins and toolbox talks work fully offline; videos need signal and say so plainly. A banner on the run screen flags outstanding training and taps straight through. The run sheet, docket and every other screen are unchanged. Needs a backend deploy for completions to persist to the office (they’re saved on the device until then).
v0.92.0
4 August 2026
- NewLearning screen — author training content for drivers — the dispatcher side of the new Learning system. A Learning item under Checks & Forms opens a screen to create, edit and retire courses: inductions, refreshers, toolbox talks, safety bulletins and client-site videos. For each you set the kind and content type, a summary/body, the audience (everyone, or specific depots, clients and asset types — each driver then sees only what applies to them), and the rules: required, gate the job (a required course can block departure, like an L&D STOP), acknowledge-only, and a refresh interval. Editing a published course re-issues it as a new version, so past completions are preserved and drivers are asked to complete the new one. Content upload (video & SCORM) plugs in with the hosting update that follows; for now a content link and text bodies work, and the screen ships seeded with placeholder courses. A front-end change for authoring; the driver-facing “My Learning” view and completion capture come next.
v0.91.0
4 August 2026
- NewFoundation for driver training & inductions (Learning) — the data model behind a new Learning system for driver-facing content: inductions, refreshers, toolbox talks, safety bulletins and client-site videos. Courses are definition-driven like the site forms — adding one is data, not code — and completions are kept as immutable, versioned records (redoing a course files a new record; a re-issued bulletin has to be re-acknowledged), the same honest pattern as the L&D checks. The clever part is the audience resolver: it answers “which courses does this driver need” across five axes — everyone, their depot, the clients and client-sites they work, and the asset types they operate — worked out from the jobs and consignments they’re linked to (a driver record carries none of these directly). Seeded with labelled placeholder content so the screens to come are demoable. This release is the model and logic only — no screens yet (the dispatcher authoring screen and the driver “My Learning” view follow); it adds a new stored collection, so it needs a backend deploy before completions persist.
v0.90.0
4 August 2026
- NewThe geofence editor now shows the live fleet on the map — so you draw a fence around where assets actually cluster instead of guessing coordinates off a blank basemap. Positions come from the same live feed as the dashboard, drawn as small non-interactive markers so one can never swallow the map click that drops a circle centre, polygon vertex or line point — and they sit in their own layer, so the map still frames the fence rather than zooming out to include a truck in Kalgoorlie. The feed is unsubscribed when you leave the screen. Only tracked asset types report a position, and that caveat stays on screen. A front-end change, live on the next site deploy.
- NewThe map popup’s speed history can now expand to 7 days — the asset popup (Tracking, Live Fleet, the dashboard mini-map and the wet-hire card) draws a 24-hour speed worm; a new 7 days button expands it, with a way back to 24h. The 7-day view is a speed-only fetch, cached separately so it doesn’t re-fetch or flicker as the map refreshes every ~15s, and the chosen window is kept per asset across those refreshes rather than collapsing back to 24h. The longer window is more downsampled, so the line uses the same adaptive gap rule as the charts — a real recording gap still breaks it, ordinary spacing doesn’t. A front-end change, live on the next site deploy.
- NewThe Lost Revenue report now names where an asset is sitting — a new Location column resolves the last-known coordinate to a named geofence or depot, distinct from the asset’s home Depot column. Where the spot isn’t named yet, a “+ Name this area” action opens the geofence editor seeded with a circle on the asset’s own position, so the library of named places (client sites, laydowns, crib stops) fills in over time and the report reads better the more it’s used. Built on a reusable resolver (
NF.areaFor) that returns the most specific area — a user fence over a depot, the smallest fence among overlaps. A front-end change, live on the next site deploy.
- NewGeofence enter/exit crossings are now kept as a durable trip log — the evaluator already raised transient enter/exit alerts to the events feed; it now also persists each crossing as a queryable record (asset, fence, enter or exit, time, position). It’s idempotent, so a re-sweep never double-counts, and it’s stored as telemetry — out of the whole-document state, like position history — so it can grow across the fleet without slowing sign-in. This is the foundation the Hazelmere→Pilbara corridor lane report pairs into trips. Needs a backend deploy; until then the app records nothing and behaves exactly as before.
v0.89.0
4 August 2026
- FixThe Odoo asset detail can now be saved — it too was too big to persist as one record — the companion to v0.88.0. The Odoo import stored the whole vehicle record against each matched asset, and with the detail on 778 assets the register (
col#assets) came to ~397KB — over the 380KB per-item guard on save (DynamoDB caps an item at 400KB), so the asset detail was rejected (413) and never persisted. It now keeps only the fields a screen actually reads — make, model, VIN, year, acquired, stage, odometer and its unit, plus the Odoo id needed to match the service history — and drops the redundant weight (the composite name, a duplicate of the plate, a constant company, a record-updated timestamp, and the near-empty driver / location / fuel / seats fields, all 0–7% filled). That takes the register to ~255KB, comfortably under the cap, with no visible change to the asset page. The register is a fixed-size fleet, so one trimmed record stays fine long-term — unlike the ever-growing service history, which had to be split up (v0.88.0). A front-end change: it takes effect on the next site deploy, after which re-importing from Odoo makes the asset detail stick.
v0.88.0
3 August 2026
- FixThe Odoo service history can now be saved — it was too big to persist as one record — the imported service history is 3,532 records (~545KB), and it was being stored as a single database item. DynamoDB caps an item at 400KB, so every save of the history was rejected (413) and the service log never actually persisted — the headline Odoo feature silently saved nothing. It is now sharded into one row per service record (each ~200 bytes), exactly the way consignments are already stored, so the per-item cap can never bite however large the history grows. Existing hand-entered records and any history written before this are read back and migrated automatically on the next save, with no duplication. Entirely a backend storage change — the app is untouched and still works with the history as a plain list. Needs a backend deploy, after which re-importing from Odoo will make the service history stick.
v0.87.0
3 August 2026
- AddOperators can run the Odoo register import without a browser — a new maintenance script,
backend/import-odoo.js, does exactly what the Settings → Asset register → Import from Odoo button does, from the command line: node import-odoo.js <apiBase> reads Odoo and the live register and reports what would change (how many vehicles matched, which are in Odoo but not the register, which matched more than one row, and the service-record counts), and --write applies it. It uses the same merge logic the screen uses (NF.mergeOdooAssets / NF.mergeOdooServices, loaded out of js/data.js), not a second copy that could drift: Odoo detail lands in each asset’s own odoo namespace, type / depot / business unit and every other collection are left untouched, unmatched vehicles are reported rather than added, and hand-entered service records are kept. It reads the document back after writing to confirm, is safe to re-run (idempotent), and never writes if a fetch fails. Like the other maintenance scripts it is a whole-document write, so it’s run when the board is quiet; the operator reviews the dry run before using --write. Tooling only — no site or backend change is required to use it.
v0.86.0
3 August 2026
- AddService due now understands plant measured in engine hours — a check against the live Odoo data found 33 of 900 vehicles whose odometer is recorded in engine hours, not kilometres: excavators, generators, cranes and the like. The service countdown was assuming kilometres for every one of them, so an hours reading like
4,300 came out labelled and forecast as if it were 4,300 km — a meaningless figure. The asset page, the service-due badge and the Service due & forecast report now read each asset’s unit and count it down in the right one: kilometres against the settled 25,000 km road interval as before, or engine hours against an assumed 500-hour plant interval, labelled “hrs” and marked assumed on screen because a genset and a crane service on very different hours. Plant is grouped into its own section of the forecast rather than dropped into a “within 5,000 km” bucket it doesn’t belong in. Where no hours interval is known, the asset’s last reading and last service still show but no due point is invented — the same honesty the report already keeps for an asset with no odometer. Road vehicles are entirely unchanged.
v0.85.0
3 August 2026
- TuneLive GPS: more of the fleet stays on the map — a measurement after v0.84.0 showed the prime-mover tier still taking about 63% of each sweep (topSwept 27 of 43), which held the live fleet at ~386 assets. The other-tracked rotation floor (
FLEET_OTHER_LEAD) is raised from 10 to 20, giving the rotations ~26 calls per cycle: prime movers now refresh over about three cycles (~35–45 seconds, still far better than the six minutes before v0.75.0) and more of the trailer / bus / light-vehicle fleet stays live on the map. Backend only; needs a backend deploy.
v0.84.0
3 August 2026
- ChangeLive GPS: the prime-mover tier no longer starves the rest of the fleet off the map — the background sweep can only complete about 46 Fleet Dynamics calls per cycle, and the prime-mover priority tier added in v0.75.0 was swept whole at the front of each cycle. With ~51 prime movers, that consumed the entire per-cycle budget, so the two background rotations — reserved behind it — got zero calls, and the live map collapsed from 790 assets to 467 as trailers, buses and light vehicles aged off it (recorded history was unaffected). The sweep now reserves a floor of calls for the untracked and other-tracked rotations at the front of each cycle, and caps the prime-mover tier so it can’t take the whole budget: the prime movers now refresh over about two cycles (~20–30 seconds, still far better than the six minutes before v0.75.0) while everything else stays on the live map. A new tunable (
FLEET_OTHER_LEAD) sets the other-tracked floor; the exact split will be tuned by re-measuring the feed after deploy. Degrades safely as before — the last good snapshot is always served. Backend only; needs a backend deploy.
v0.83.0
3 August 2026
- AddNew report: Hazelmere → Pilbara lane volumes, counted from GPS trails — a new Lane volumes report (Reports → Lane volumes — Hazelmere → Pilbara) counts completed line-haul trips from the Hazelmere depot to the Pilbara depots (Port Hedland, Karratha, Newman, Newman Airport, Tom Price), broken out per day, per week and per month and split by destination, with a trend line. It is derived from tracked prime movers' recorded GPS position trails, not from consignments: a trip is counted when a truck's fixes put it inside the Hazelmere fence and then inside a Pilbara-destination fence within 3 days (each fence 5 km around the depot). One-way only — a Pilbara → Hazelmere backload is not a lane trip — and de-duplicated to one trip per truck per departure day per destination. Scope is deliberately narrow and stated on screen: tracked prime movers only (the line-haul fleet, the only assets with dense enough trails); other and untracked assets are invisible, not zero. The report reaches back only as far as the recorder has run (the earliest recorded date is shown), and because a trip needs both ends recorded, a coverage gap can miss one — so every count is a floor, not an exact tally, and every figure is labelled as GPS-derived. Kalgoorlie is excluded (not Pilbara). If it becomes slow as history accrues, moving the trip detection server-side is the follow-up.
v0.82.0
3 August 2026
- FixThe API now locks itself down if its access token is ever missing, instead of opening up — the service that decides whether a request to the backend is allowed used to fail open: if no access token was configured on the server, it let every request through. That meant a deploy that never stored a token would silently leave the whole database world-readable and world-writable. It now fails closed — with no token configured it denies every request and logs a clear warning, so a misconfiguration is loud rather than silently open, and the same when the token store can’t be read. Nothing changes for the live site today, because a token is configured (requests without it already get a 403); this only removes the dangerous “no token ⇒ allow everyone” path. Backend only — needs a Deploy backend run, and a token must remain stored or the API will (by design) deny everyone. This is defence-in-depth: the shared token still ships inside the public site bundle, so it is a speed-bump against anonymous writes, not per-user login — real per-user authentication is tracked separately.
v0.81.0
3 August 2026
- AddMaintenance script to slim the sign-in database read — removes leftover tracking data from the main table — live position history, the daily driving summaries and the cached road speed limits used to live in the same database table as the operational data (jobs, consignments, forms). They have since moved to their own table, but the old copies were left behind, and although sign-in is written to skip them, the database still has to read past every one of them on the way through — which is a large part of why opening the apps has been slow (measured this session: the state read took about 8.9 seconds for roughly a third of a megabyte of actual data, most of the time spent reading tracking rows it then discards). The new
backend/purge-legacy-telemetry.js is a careful, one-off clean-up an operator runs by hand. It reports only by default — it counts the leftover rows and their size and shows a few examples, changing nothing — and only deletes when run with --write, after which it reads the table back to confirm the rows are gone. It can only ever delete tracking rows: a hard safety check confirms every row’s key before each delete, so an operational record can never be touched, and re-running it is safe (it simply finds nothing). Deleting the tracking history is a deliberate, reviewable step — the operator runs the report first and decides. Backend maintenance only; nothing in the apps changes and no deploy is required.
v0.80.0
3 August 2026
- ChangeSuggest types now recognises prime movers named by brand alone — the asset register’s Suggest types helper reads Fleet Dynamics’ description of each vehicle to propose a type for the ungrouped ones. A review of the live register found it was missing a whole class of prime mover: the ones named just by their make — “HAZ - MACK”, “MACK - Super-Liner (110T)”, “KTA - Volvo S/Cab”, “PHE - MAN Sleeper Cab”, “Mercedes (150T)” — rather than by a model it already knew (Cascadia, K200, T909…). Left blank they drop off live tracking; worse, one reading “truck” could be mis-suggested as a rigid. It now reads the make: Mack and Freightliner (which build essentially only prime movers here) count on the brand alone, while makes that also build rigids, buses and vans — Volvo, Mercedes, MAN, Scania, DAF, Iveco — count only when a prime-mover sign sits alongside the brand (a sleeper or S/Cab, a Super-Liner, a road train, or a road-train tonnage of 50T or more). So a “Mercedes Sprinter” is still a van and a plain “Volvo tray” is still a rigid; the make on its own is never enough for those. This only changes what Suggest types proposes — grouping still needs a person to accept it — so it is safe, and it advances the ungrouped-register cleanup (#74) without finishing it: the status-note rows (Spare, U/S, Faulty…) still can’t be classified from their text, and the regrouping itself remains a human review.
v0.79.0
3 August 2026
- AddGeofences can now be a line you cross, with a direction — alongside a circle around a site and a traced boundary, you can now draw a line (a tripwire): click along the map to drop each point, and an alert is raised when a tracked truck crosses it. A crossing carries a direction — the first and last points you drop are labelled A and B on the map, and you can fire on a crossing either way, only A → B, or only B → A — so a one-way boundary (leaving a site, entering a restricted stretch) can be watched without alerting on the return trip. It fires once per crossing, worked out from the truck's own movement between two GPS fixes, so a stationary truck or one running alongside the line never trips it. Like the area fences, a line can route to the dashboard and the Events log (which now spells out the direction), scope to particular assets / types / depots, and carry an in-cab driver advisory — a banner and spoken message the moment the driver crosses, evaluated on their own device so it works with no signal. Still to come: corridor / dwell / speed-in-area zones, and email / SMS / webhook routing.
v0.78.0
3 August 2026
- Perf
GET /state and GET /fleet/rollup are gzipped on the wire — both are read as JSON and neither was compressed. /state is fetched at boot on every sign-in (measured 333 KB, ~8.9 s) and /fleet/rollup is pulled by Overview, Assets and Events (measured 930 KB, 4.8–8.8 s). The Lambda now gzips each response when the caller advertises Accept-Encoding: gzip (every browser does, automatically and transparently) and returns byte-identical plain JSON otherwise — the same opt-in helper /fleet/history already uses. /state drops to roughly 50 KB on the wire; the response body is unchanged, so a client that can’t inflate (and the driver service worker, which never caches /state) still gets exactly what it did. These are the two deferred transfer-size follow-ups from the #108 live-API perf audit.
v0.77.0
3 August 2026
- FixTelemetry screens no longer go blank under their own request burst — the Utilisation, Speeding, Assets and bus Movement reports each fire many position-history reads at once (measured: Utilisation 18 requests, Speeding 15, Assets 5). Each request succeeds on its own, but fired all together they pushed the backend past its limit and it shed some as transient errors; because the app fired every chunk at once with no cap and no retry, a shed request became a hole and, when enough were shed, the whole screen came up empty. History reads now trickle through a small pool (a few in flight at a time) instead of all at once, and both the history and rollup reads retry a transient overload (503 / 429) with a short backoff before giving up — while a genuine bad request (e.g. 400 / 404) still fails fast and is not retried. The net effect is that a burst which used to blank the screen now fills it, at a small latency cost. Also addresses the slow / blank bus Movement report (129 buses is a large fan-out). No change to what any screen requests or shows; trimming the large rollup payload is a separate follow-up.
v0.76.0
3 August 2026
- FixSigning in no longer loads the whole database twice — a performance audit found that opening the dispatcher app fetched the full application state twice at start-up (each around a third of a megabyte and several seconds), which added a needless delay to every sign-in. The first read is the one the app has always done; the second was the automatic 5-second save quietly kicking off its own read because the first one had not finished yet on a slow connection. Start-up now shares a single read — if one is already under way, anything else that needs the database waits for it rather than starting a second — so the app loads the state once and gets to a usable screen sooner. Nothing about how data is saved, merged or protected has changed; this only removes the duplicate download. Two known start-up costs are unaffected and tracked separately: the response is not yet compressed, and the read itself is slow on the server side.
v0.75.0
3 August 2026
- ChangeLive GPS: prime movers now refresh close to every 15 seconds — the background sweep that keeps the Live Fleet map current can only make so many Fleet Dynamics calls per cycle, so with ~770 assets in tracked types the whole tracked set was rotating and even the prime movers were being refreshed only about every six minutes (measured: median prime-mover position age 7 minutes). The sweep now runs a third, top-priority tier: the asset types named in the new
FD_PRIORITY_TYPES setting (default prime, ~51 prime movers) are swept whole every cycle, ahead of the two background rotations, so the trucks dispatch watches most closely stay live. The rest of the tracked fleet and the untracked fleet keep rotating behind them — each cycle still advances both, so nothing ages off the map or stops recording history — and a guard makes the top tier itself rotate if it is ever configured larger than one sweep can hold, so it can never consume the whole cycle and starve the rest. FD polling concurrency was raised from 5 to 10 (still well within a gentle rate) so the top tier fits in one cycle with slots to spare; both knobs are tunable and the effect is measurable on the feed (new priorityTop / topSwept diagnostics). Degrades safely: a too-aggressive setting can only cause more harmless deadline aborts — the last good snapshot is always served — never an error. Backend only; needs a backend deploy.
v0.74.0
3 August 2026
- AddGeofences can now warn the driver in the cab — a banner and a spoken message — a geofence can carry a driver advisory: set a short message (“Slow down — reversing zone”, “Watch out for the dip”) when you draw or edit the fence, and the driver sees it as a large, high-contrast banner on their Drive screen and hears it read aloud the moment they enter the zone. The banner clears itself when they drive out. It is evaluated on the driver’s own device against its own GPS, so it works in a dead zone with no signal — the voice prefers an on-device voice for the same reason. The driver can mute the voice with a one-tap control (the banner still shows); the voice is unlocked the first time they tap into the app, as phone browsers require. It fires once per entry and is steadied by the same boundary buffer the dispatcher alerts use, so a GPS track wobbling on the edge doesn’t repeat it. Only fences you mark as a driver advisory, that are enabled, and that apply to that driver’s vehicle are evaluated. The dispatcher’s dashboard / Events-log routing is unchanged and runs alongside it. Still to come: line crossings with direction, and email / SMS / webhook routing.
v0.72.0
3 August 2026
- NewService Details report under Assets — service-due list and per-depot forecast — a new Service Due screen (Assets nav, the Assets hub and Reports all link to it) answers two questions in one place. First, a fleet-wide list of what is overdue or coming due, most-overdue first, with each asset’s depot, last service and kilometres over / until due. Second, a forecast pipeline per depot — how many of each depot’s assets fall due within 5,000 km, within 10,000 km, or later — so a depot manager can see the work coming rather than only what has already slipped. It states its own limits plainly, in the house style: a countdown needs both a service record and an odometer, so the page reports how many assets have each (e.g. “N of M have a service record; K have an odometer reading”), and assets with no odometer or no service record are shown in their own sections rather than folded into “not due” — a fabricated countdown is never shown. A booking that has not been carried out does not reset the countdown (the same rule the asset page already applied to Odoo’s planned services, now shared as one predicate so the two cannot drift). Every figure is labelled an estimate from the recorded odometer and the service interval — a prompt to check, not a workshop record. Service history and odometers fill out further once the Odoo grants land (#86).
v0.71.0
3 August 2026
- ChangeAssets navigation tidied up — Lost Revenue is now a menu item, and the Assets hub is folded into Fleet Overview — the Lost Revenue report (idle tracked assets and the standing cost each is carrying) now has its own entry in the Assets menu, alongside Overview, Composition, Utilisation and Movement, so it is reachable directly rather than only from Reports and the old hub. The separate Assets item under Shared has been removed and its two useful pieces — the fleet KPI strip (assets, tracked live, reporting now, moving, ungrouped, alerts to action) and the Needs attention list (speed alerts to action, overdue service, assets not moved in 3+ days, under-utilised assets and ungrouped assets, worst first) — moved onto the Fleet Overview page, under the coverage caveat. Opening the old
#/assets link now lands on Fleet Overview, so existing bookmarks still work.
v0.70.0
2 August 2026
- FixFleet Composition page no longer leaves a big empty gap between its columns — the page laid its sections out as fixed two-column rows, pairing a tall card (By type, ten rows) beside a short one (By depot, six), so the short card left a large stretch of dead space below it before the next section could start and the columns read as misaligned. The sections now flow as a masonry: each card is sized to its own content and a short one no longer holds the row open, so the page packs top-to-bottom with no dead space. It reflows to a single column on a phone, and looks right whether or not Odoo is connected (the make / model / age / odometer sections are still empty until then). Layout only — the figures each section shows are unchanged.
v0.69.0
2 August 2026
- ChangeDriver L&D form: trailer picker orders real trailers by their live GPS — on the driver app’s Load & Dimensions check, the trailer list is now sourced from the real physical trailers on the asset register (the ones imported from Fleet Dynamics) and ordered by the actual distance from the driver to each trailer’s last-reported GPS position, so the trailer being hooked onto — almost always the closest — is at the top and is what gets recorded, improving the compliance record. The closest handful are offered as quick-pick chips while every trailer stays findable by typing, so a driver in an unusual spot can still pick theirs. It never blocks: if the driver’s GPS is denied it falls back to the job’s origin-depot order as before; if the live feed is slow or unavailable it orders by the depot nearest the driver; and before the register has synced it uses the curated list — and because the driver’s fix and the fleet feed both arrive a moment after the form opens, the picker re-orders itself once they land. Trailer positions are last-reported (can be minutes old) and about 30 of ~190 trailers don’t report at all, so the picker says both plainly. Supersedes the depot-level approximation that was proposed for this (it used the nearest depot rather than each trailer’s own position).
v0.67.0
2 August 2026
- FixNew depots now appear on the live site — a depot added in the code (Newman Airport, Kalgoorlie) was vanishing on the deployed site, because the stored copy of the depot list was replaced wholesale over the code’s on every sync, and that stored copy was old and missing them. Depots are now merged by id rather than replaced: the database stays the authority (a depot added or edited in Settings still wins and persists), while a depot that only exists in the code is kept rather than wiped, so it shows up straight away. The one trade-off is that a change to an existing depot’s details made only in the code won’t override the database — that is what “the database is the authority” means, and any real edit is made in Settings. Fixes the live site on the next front-end deploy with no backend deploy and no database change.
v0.66.0
1 August 2026
- FixFitness-for-work and prestart submissions can now be opened to review — on the Checks & Forms screens the “Submitted checks” rows were not clickable, so a filed fitness-for-work or prestart check could not be opened to see its answers, declarations and photos; only the connote link responded, and it navigated away to the consignment. Each row now carries a View ↗ action (the whole row is clickable, and keyboard-operable) that opens the submission in a read-only detail view showing the declarations as given, the STOP / non-conformance record with the manager advice recorded (who was told) and the load photos. The existing L&D review queue and its office sign-off are unchanged — the same viewer simply grew a form-agnostic read-only mode that serves fitness, prestart and L&D alike, rather than the L&D-only review it was.
v0.65.0
1 August 2026
- FixUntracked assets no longer flicker on and off the live map — the shared fleet snapshot ages every position out after 15 minutes, but an asset whose type isn’t ticked “track live” is only refreshed as a slow rotating window reaches it, and a full rotation lap takes longer than that. Its last-known position therefore expired before the rotation came back round — it dropped off the map, then reappeared on the next visit. Tracked assets, which are swept every cycle, keep the tight 15 minute expiry; the rotating remainder now hold their last position for a rotation-safe hour, so it survives between visits instead of blinking out. Nothing else about coverage, the rotation or which assets are tracked changes. Harmless today because so few untracked assets report, but it would become visible if trailers were tracked. Takes effect with a backend deploy.
v0.64.0
1 August 2026
- FixThe fleet-history read shrugs off a passing database throttle — the movement, utilisation and speed screens fetch recorded history for many assets at once, fanning out into several parallel batches. If one of those batches hit a brief DynamoDB throttle it used to fail outright, dropping a whole chunk of assets from the page (which still drew, just missing a truck or two). Each batch now retries a throttle a few times with a short, jittered back-off before giving up, so a transient throttle no longer costs any assets. If a throttle genuinely persists the page degrades exactly as it did before — nothing crashes — and a real fault (a bad request) still fails fast without wasted retries. Diagnosing the underlying throttle remains a CloudWatch task; this only makes the page more resilient to it. Goes live with a backend deploy.
v0.62.0
1 August 2026
- AddGlobal search now finds assets — the top-bar search (previously connote, quote and client only) also returns vehicles and plant, so a dispatcher can jump straight to any asset’s page by number or plate. It matches on every identifier the register carries — the FD unit id, the plate, the free-text description, the type and depot, and (once Odoo is imported) make, model and VIN — because the plate field alone is often blank or a status note (“SPARE”, “U/S”). Results carry a yellow Asset chip and a label that disambiguates (e.g.
NF1000 · Prime mover · Port Hedland), a blank-plate row falling back to its unit id.
- ChangeSearch stays useful across types — the register is far larger than the other collections, so the asset pass ranks exact id/plate matches first and is capped at four results, keeping a common substring from crowding out a connote in the shared dropdown.
v0.61.0
1 August 2026
- AddNewman Airport added to the depot list — a new Newman Airport yard sits alongside the existing Newman (Whaleback) depot, with its own Depots sub-menu entry and per-depot page. Everything flows from the depot register: the menu, the page at
#/depot/NWA and the live in-yard list all generate themselves from the one row. The in-yard list uses the default 4 km depot circle around the airport coordinates until a drawn yard boundary lands.
v0.59.0
1 August 2026
- ChangeThe asset detail page has been redesigned for usability — instead of one long single-column scroll through nine sections, the page now opens with a summary strip that answers the top questions once (speed and position now, tracked or not, odometer and its source, next service, last-7-day distance and utilisation, and standing cost per day), then splits the detail into two columns on wide screens that collapse to one on a phone. Reaching Service or Jobs no longer means scrolling past Identity, Odoo and the maps.
- AddTabs group the textual detail — the left column carries Overview (identity and the From-Odoo record), Service (service history, the countdown and the documents & expiries) and Commercial (jobs and consignments), keyboard-operable with the arrow keys. The “where it’s been” map, live position and 7-day activity stay in the right column, always visible.
- ChangeEmpty sections collapse rather than showing blank tables — the From-Odoo panel only appears once an Odoo record is matched, and the honesty rules are preserved throughout: no figure is shown as measured when it wasn’t (no fabricated 0 km or 0 L). The map, its 24h/7d toggle and the recorded-history figures are unchanged.
v0.58.1
1 August 2026
- FixImport from Odoo now works — the importer referenced an undefined
API and failed with “API is not defined” the moment it was pressed. The fault was latent until Odoo was connected (the importer had never reached a live backend before); the Odoo module now resolves the backend address the same way every other integration does.
v0.58.0
1 August 2026
- AddA Fleet Composition page — a new page under Assets (also linked from the Assets hub and Reports) that breaks the whole asset base down every worthwhile way, with counts and each cut’s share of the fleet: by type, depot and business unit, which are tracked live, and which are priced for cost planning. It also breaks the fleet down by make, make-and-model, age band and odometer band — but those come from Odoo, so each of those cuts states plainly how much of the fleet it actually covers (“make known for N of M assets”) rather than implying the whole fleet, never folds an unknown into a real bucket, and reads as empty until Odoo is connected. It also surfaces how many register assets are matched to an Odoo record so the gap can be worked through.
v0.57.0
1 August 2026
- Fix“0 km driven” while an asset was clearly moving — the Utilisation page, the Assets hub and the asset page’s “Where it’s been” readout could show 0 km driven next to hours of wheels-rolling time and 100% of tracked time moving. Those screens fetch a lightweight speed-only history (time and speed, no GPS position, to keep the pages fast), and the distance was being worked out from the positions — which weren’t there — so it came out as zero. Distance is now worked out from the recorded speed over time, so it is real on every one of those screens and the numbers agree with each other again. A recording gap still adds no distance, and a window with gaps is still reported as a floor, not padded.
- FixThe blue history track is visible again on the asset page — when an asset’s current live position was far from where its history was recorded (a unit that had since driven away, or a jumped GPS fix), the map zoomed out to fit both and shrank the actual track to an invisible dot. The map now frames the recorded track itself; the live marker and its projection are still drawn, they just no longer drag the view away from the trail.
v0.55.0
1 August 2026
- AddRegistration, insurance and lease expiries imported from Odoo — the Odoo import now brings in each vehicle’s contracts (
fleet.vehicle.log.contract) and maps them onto FleetView’s existing document-expiry outlook, alongside the hand-entered registrations, permits and inspections. Each contract is classified as registration, insurance or lease/finance and shown on the asset page’s new Documents & expiries section, on the fleet-wide expiry outlook in Reports, and in the compliance snapshot.
- AddContracts follow the same rules as the service history — matched to the register through either identifier (never guessed), replaced on every re-import while records entered by hand are kept, and a draft or closed contract is marked rather than counted as a live expiry. Only each asset’s current contract of a kind is counted in the outlook, so a truck’s years of renewed registrations don’t flood it.
- ChangeRead-only and resilient — the contract read is discovered by field shape (not a hard-coded name list), degrades to “nothing to import” if the key can’t read the contract model, and drops a single restricted column rather than failing the whole read. Going live still needs a backend deploy and the Odoo API key granted read access to the contract model.
v0.54.0
1 August 2026
- ChangeThe Speed Alerts page loads much faster — it no longer downloads a week of driving history for every tracked asset just to build the over-limit table. It now reads the small daily summaries first (which already carry each asset’s top speed) and fetches the detailed history only for the assets that could actually have been over a limit — on a typical week, a fraction of the fleet. Anything slower than 45 km/h can’t exceed even a 40 zone, so it is skipped, exactly as the Events screen was already changed to do. If the summaries can’t be read, it falls back to the full read as before, so nothing is ever missed. No change to what the alerts show; the same reason-to-look-not-a-finding caveats about posted limits still apply.
v0.53.0
1 August 2026
- AddA Depots menu with a page for every yard — a new top-level Depots section in the sidebar, with one entry per yard. The list builds itself from the depot register, so adding or removing a yard adds or removes its page automatically. Each page shows the yard’s cameras and a live list of every asset currently on site.
- AddWho’s in the yard, live — the depot page lists the assets currently at that yard, updated live from the fleet feed, each linking to its asset page and its position on the map, with a second list of trucks approaching. “In yard” today means within the 4 km depot geofence circle — the page says so; a drawn yard boundary is a later increment.
- AddYard cameras (placeholders for now) — four labelled camera tiles per yard, laid out ready for real feeds. They show a clear “no feed configured” state: wiring an actual video source (site CCTV/NVR or a cloud stream, with credentials held in the backend) is a separate integration still to be chosen.
- ChangeDepot list corrected to the operational yards — Bunbury has been removed (it’s a South West delivery locality, not a yard — pricing is unaffected) and Tom Price and Kalgoorlie added. A depot page honours the
?wall yard-monitor view.
v0.52.0
1 August 2026
- AddNew “Lost revenue” report — tracked assets that haven’t moved in the last 24 hours — reached from Reports and the Assets hub. One row per idle asset: the asset, its type and depot, how long since it last moved, and its last known location. Assets sitting still the longest are listed first. Judged from the daily movement summaries, so it covers the tracked fleet only — the coverage is stated in full at the top, the way the fleet overview does, so it never reads as a statement about the untracked half of the register.
- AddWhat the idle fleet is costing to own — each idle asset shows its standing cost per day (finance, rego, insurance, depreciation) and the report totals it. It is a planning estimate from WA benchmark rates, not Northfleet’s accounts, and a type with no rate configured is named and excluded rather than counted as free — the same refusal the cost figures elsewhere already make.
v0.51.0
1 August 2026
- AddThe Speed Alerts page now opens on an at-a-glance dashboard — three new panels sit above the alerts workflow. Fastest right now lists the top 20 assets by current speed straight from the live GPS feed, each with its limit and how far over it is, and a map pin; a row over the limit is red, and it refreshes with the feed. Highest speed — last 24 hours and last 7 days are peak-per-asset leaderboards. The over-limit alerts table, repeat offenders and “since the conversation” panels are unchanged, below the dashboard.
- ChangeThe top of the page paints immediately instead of on a “Loading…” — the two peak leaderboards read the small daily summaries, which already carry each asset’s top speed, rather than the several megabytes of week-long fleet history the alerts table needs. That heavy read now fills in the alerts underneath while the dashboard is already up. The current-speed board also works on a depot wall display, auto-refreshing like the live map.
- ChangeThe live board is measured against each asset’s own limit — a bus or light vehicle isn’t held to a road train’s figure. Where a posted road limit is already known for where a truck is, the lower of the two applies and the row says the limit is signed; a peak above 110 km/h is over the limit on any road in WA and is marked so. Until the feed and the summaries have actually loaded, the panels say they are waiting rather than showing an empty board as if nothing were speeding.
v0.50.1
1 August 2026
- ChangeThe sidebar “Asset Details” item is now labelled “Fleet Dynamics” — same screen, same icon, same place in the Assets area; just the name on the nav item.
- AddA “Technology Demonstration” line under the Transport Manager name — a small subtitle beneath the app name in the sidebar and on the sign-in screen, marking the app as a prototype.
v0.50.0
1 August 2026
- AddDraw your own geofences and be alerted when a truck enters or leaves one — a new Geofences screen under Assets. Draw a circle around a site (drop a centre, set a radius) or trace a boundary point-by-point on the map, then choose whether an alert fires on enter, exit, or both. This is on top of the built-in depot arrival alerts, which are unchanged. Alerts appear on the dashboard and in the events log, coloured by the severity you set.
- AddLimit a fence to particular assets — a geofence can apply to the whole fleet, or be narrowed to chosen asset types, depots, or specific units. Leave the scope empty and every tracked truck is watched against it.
- AddA boundary buffer stops edge-of-fence flapping — a truck parked right on a fence line, where GPS naturally jitters in and out, raises one crossing rather than a stream of them. The alert fires on the way in and won’t report an exit until the vehicle has clearly moved away.
- ChangeGeofences see the tracked fleet only — a fence is evaluated against live positions, and only assets whose type is tracked live report their position, so the screen says so up front. Two things are deliberately left for a later increment: an in-cab advisory on the driver’s own device, and routing an alert to email, SMS or a webhook — for now both alert options file into the dashboard and events log.
v0.49.0
1 August 2026
- ChangeThe fleet movement page now remembers your filter for the rest of the session — it used to reset to prime movers every time it was opened, even if you had just narrowed it to a depot or another asset type moments before. Picking a filter now sticks while you keep browsing the app, the same way the wet hire board and a driver’s run day already do; a fresh page load still opens on prime movers.
v0.48.0
1 August 2026
- ChangeThe Events screen no longer downloads the whole fleet’s week of tracking every time it opens — the page files speed alerts into the events log alongside geofence and delivery events, and to do that it was pulling roughly three and a half megabytes of every tracked asset’s recorded speed — a background job wearing a page load. It now reads the small daily summaries first, which already carry each asset’s top speed, and fetches the detailed history only for the assets that actually drove fast enough to have possibly broken a limit. The speed alerts that appear are unchanged — same events, same locations, same times — they just cost far less to gather. If the summaries aren’t available it falls back to the old behaviour rather than missing anything.
v0.47.0
1 August 2026
- ChangeOvernight recording and the current tracking-storage layout are now on by default — a backend deploy setting. Both used to default to off / the older layout, and because a deploy applies whatever value is passed, forgetting to re-pass them silently turned overnight tracking off and reverted the storage the reports read from — so a 24-hour movement chart quietly went back to showing only the hours someone happened to have FleetView open. The safer sticky value is the finished one, so that is now the default; a deploy that changes nothing else no longer undoes them. The permission that once forced overnight recording to default off has since been granted, which is what makes on-by-default safe.
- ChangeBoth are still fully reversible — recording can be switched off, and the storage layout rolled back, by passing the old values explicitly on a deploy. Nothing about the data or the screens changes; this is purely which value sticks when a deploy doesn’t say otherwise.
v0.46.0
1 August 2026
- ChangeParked assets are recorded a little more often, so their tracking lines stay unbroken — a stationary vehicle used to get a position every 13 minutes, which left barely any margin against the 15-minute limit at which a chart treats a gap as “stopped reporting”. On a busy day that gap could stretch past 15 minutes and break the line for a truck that was simply parked. Idle recording now happens every 10 minutes, giving a comfortable 5-minute margin. Takes effect on the next backend deploy.
v0.45.0
1 August 2026
- ChangeThe sidebar is now organised by business division — the menu has a new top level grouping every screen under the division it belongs to: Transport (with Sales & freight and Operations inside it), Wet Hire, Dry Hire, Plant & Equip, Checks & Forms, Assets and Shared. Dashboard stays pinned at the top. Each division folds away like the existing groups, and both the division and the group holding the screen you are on open automatically so nothing is ever hidden behind a fold.
- AddAn Assets area brings the asset screens together — Overview, Asset Details, Tracking, Speed, Utilisation and Movement now sit under one Assets division rather than being reached only from the Assets hub. The screens themselves are unchanged.
- AddDry Hire and Plant & Equip appear as divisions — they have no screens yet and say so when opened, so the shape of the business is visible in the menu ahead of the work that fills them.
- ChangeA collapsed division still shows its alerts — if an unread badge (a job in the inbox, an invoice to review, a message from a driver) is hidden inside a folded division, its header carries a dot so the alert isn’t lost.
v0.44.0
1 August 2026
- ChangeTracking-history downloads are now compressed — the movement and speed screens fetch the fleet’s recorded position history, which on a whole-fleet view is several megabytes of data. The server now sends that response gzip-compressed to any app that can unpack it (all modern browsers do), which is typically an 80–90% reduction in what goes over the wire — so those screens load faster, especially on a slow connection. Anything that can’t handle compression still receives exactly the same data as before, uncompressed.
v0.43.0
1 August 2026
- FixA safeguard against a screen quietly downloading the whole fleet’s tracking history — the tracking-history reader always narrows a request to the assets a screen actually needs. Asking for no assets at all — the one path that would fetch roughly eleven times what any screen shows, and could exceed the server’s time budget once continuous recording is on — now logs a clear developer warning instead of doing it silently, so a future screen that forgets to name its assets is caught in testing. Asking for an explicitly empty set still correctly returns nothing.
v0.42.0
1 August 2026
- AddThe speed alerts page now looks up posted limits itself — until now it could only use a road’s limit if that stretch had already been looked up by somebody opening an individual asset’s page, because the alerts list reads speeds without positions and so had nothing to look a limit up by. In practice that meant it never used them: measured on the live fleet, none of 4,606 recorded positions over six hours had a road limit attached. The page now fetches positions for the assets that could actually breach a posted limit and resolves the roads itself.
- ChangeIt says what it checked and what it didn’t — how many assets were checked against the road, how many stretches of road were resolved, and anything left measured against the vehicle’s own limit only. A page that checks some assets against the road and the rest against their own limit reads as though it checked them all.
- ChangeOnly speeds that could actually breach a limit are looked up — below 45 km/h nothing can exceed a 40 km/h zone or higher, so looking the road up buys nothing and costs a request. The trade-off, stated because it is a real gap: a 10–30 km/h zone (car parks and similar) is not checked on this page. An individual asset’s page still resolves every position.
- FixA road looked up for the first time now starts being used within minutes — positions are tagged with the road’s limit as they are recorded, and a road that had not yet been looked up was being remembered as “no limit” for as long as the recorder kept running, so a newly available limit never took effect. “We haven’t looked this road up yet” and “this road has no signed limit” were being stored as the same thing.
v0.41.0
1 August 2026
- AddTracking history is now kept for good, not just seven days — every day a tracked asset drives is retained, so reports can look back as far as the fleet has records rather than losing everything older than a week. It stays fast to read because it’s stored in two tiers: a small daily summary per asset (distance, time moving, a speed profile) that is the permanent record behind the reports, and the full high-detail GPS breadcrumb that the map track draws from. Both are now kept; a read only ever pulls the window it asks for, so keeping more history doesn’t slow anything down.
- AddThe asset map shows the last 24 hours as a track, with a button for 7 days — the “Where it’s been” map now carries a 24 hours / 7 days toggle. It opens on the day, and switching to the week redraws the track instantly without asking the server for anything — the whole week is already loaded, so the button just re-slices it.
- AddA “wheels rolling” readout on the asset page — how long the asset was actually moving and how far it drove, over whichever window the toggle above is set to. It follows the same 24 hours / 7 days button as the track, so the number and the line on the map always describe the same span. Where the unit stopped reporting for a stretch, that time is excluded and the figures are called a floor rather than padded out.
v0.40.2
1 August 2026
- FixPosted speed limits were never being remembered at all — found by checking the previous fix against the live service. The store of looked-up limits was being written in a form the database rejects, and the rejection was being swallowed, so not one limit had been saved since the feature shipped. Two consequences: Main Roads was asked again for every stretch of road on every screen refresh, and — because recorded positions take their posted limit from that store — no recorded position had ever had one attached, so the speed alert screens were falling back to the configured limit even where the road’s limit was known. Alerts themselves were correct throughout; they were simply measured against the vehicle’s own limit rather than the road’s.
- ChangeThe lookup now reports how many limits it saved — the reason this went unnoticed is that a store which silently never writes looks exactly like one that hasn’t been asked about that road yet. Both read as “nothing cached”. It now says how many were stored and how many failed, so the difference is visible.
v0.40.1
1 August 2026
- FixRoads with no signed limit are no longer looked up again every time — on an unsigned road, Main Roads’ answer is the statutory default, which recites both the built-up and open-road limits and so states neither. That is a settled answer about the road, not a value we failed to read, and it can be remembered. It was being treated as unreadable and therefore never cached, so the same stretches were re-requested from Main Roads on every screen for as long as the fleet drove them. Measured over ten sampled positions it affected two, both of them depots — the places assets sit longest.
- FixAnd the same stretch of road is now judged the same way every time — where several road segments meet near one position, whether that stretch was remembered depended on which segment Main Roads happened to list first, which is not something they guarantee. The answer was stable in their data and unstable in our use of it.
v0.40.0
30 July 2026
- AddAsset information imported from Odoo — the asset register now has a second source. Fleet Dynamics knows where a truck is; Odoo is the business’s record of what it is. Asset register → Import from Odoo brings in the name, make and model, VIN, odometer, acquisition date, stage, driver on record and location, and shows them in a From Odoo panel on each asset’s page.
- AddService history — every service Odoo holds against a vehicle: date, work done, odometer, who did it, cost and invoice reference. This is the first real source for the service section on an asset’s page, which until now had only sample data behind it, and it feeds the existing distance-based “next service due” countdown. A record that is a booking rather than completed work is marked as such, so a planned service can’t read as one that has been done.
- AddThe import reports its exceptions rather than just a total — two systems that number assets differently never match completely, and the useful output is the list of what didn’t. Vehicles Odoo has that the register doesn’t are listed to be worked through, with a button to add them; vehicles whose plate appears on more than one register row are listed as needing the right row picked by hand, and are left alone rather than joined to whichever came first.
- ChangeIt never overwrites a grouping you have made — type, depot and business unit are 1,189 decisions no import can reproduce, so Odoo’s data lands in its own section of each record and nothing above it is touched. Re-importing is safe and repeatable; a service record deleted in Odoo disappears here on the next import, while anything entered in FleetView by hand is kept.
- ChangeRead-only, and enforced in the code rather than trusted to the login — the adapter will not call anything that could change data in Odoo, so nothing FleetView does can write back. The API key is held in AWS Parameter Store and read by the backend at runtime; it is never in the site’s configuration, which is public.
- ChangeAn odometer now says where it came from — the GPS unit’s live reading is used when there is one, and Odoo’s stored reading otherwise, labelled with the date it was written. The distinction matters: measured against a reading from three months ago, a truck that has run since looks closer to its service than it is, which is the wrong direction to be wrong in. Odometers Odoo records in miles are converted.
v0.39.0
29 July 2026
- AddSpeed alerts are measured against the posted limit for the road — not just against the limit configured for the asset. Posted limits come from the Main Roads WA Legal Speed Limits dataset, read through the backend and cached, so the same stretch of highway is looked up once for the whole fleet rather than by every screen. Each alert says which limit it was measured against: signed where the road’s limit was the binding one, policy where the asset’s own was.
- AddThe binding limit is the lower of the two — which is the point of the exercise. A road train restricted to 90 is still restricted to 90 on a 110 highway, so the posted limit never raises the trigger; equally, in a 60 zone the road governs rather than the truck’s 90. Taking the road’s limit as simply “the” limit would have stopped alerting on exactly the roads where a heavy vehicle is most able to speed, and done it silently.
- AddAnything over 110 km/h is flagged as over the limit on any road in WA — 110 is the highest limit posted anywhere in the state, so that alert holds whatever the road data says and whether or not there is any for that stretch. It also works as a sanity check on the data: a posted limit above 110 is a bad record, not a fast road, and is discarded rather than used to licence a truck.
- AddSpeed alerts now reach the events log from every screen that works them out — before this they were filed only if somebody opened the speed-alerts page or the Events page, so a dispatcher watching Events could miss a truck at 126 km/h entirely. Opening the Assets hub or any asset’s own page files that asset’s alerts too. Each event says in its own words which limit it was measured against, and whether it was above 110, because that is where somebody acts on one without the speed screen’s explanation in front of them.
- AddSpeed alerts on the dashboard, and on each asset’s page — a Speed alerts tile at the top of the dashboard linking through to the full list, and a link to it from the speed events on an asset’s page. The tile shows the number outstanding once alerts have been worked out; it shows a dash and “not checked yet” rather than a zero when they haven’t, because a dashboard reading “0 speed alerts” while trucks were over the limit is worse than one that admits it hasn’t looked. Each asset’s own speed events carry the same signed / policy / any road markers as the full list.
- ChangeWhat the speed screen claims, and what it doesn’t — Main Roads state that the dataset is not maintained for operational purposes, may not match the signs on the road, and that the sign is the only enforceable limit. The screen says so, and a posted-limit alert is presented as a reason to go and look rather than as a finding. Where a road has no data, or the service is unreachable, alerts fall back to the configured limit exactly as before — a speed alarm must not stop working because someone else’s system is down.
- AddA 7-day speed graph on the asset page, under the 24-hour one — two charts answering two questions: what the truck did today, and whether today is normal for it. The week is labelled by day, which the previous chart wasn’t: it was labelled every three hours regardless of how long a span it covered, so a week of history read as a 24-hour chart of an unidentifiable day.
- FixBoth graphs now cover a fixed window ending now, rather than however much data there happens to be — an asset with 40 hours of history was drawn as a 40-hour chart under a heading saying 7 days. A fixed window also shows the silence: an asset that stopped reporting three days ago now looks like three days of nothing, instead of a full chart that quietly ends early.
- FixA long window no longer draws gaps that aren’t there — a week of history comes back thinned out, so points sit further apart than they were recorded. Judged against the fixed 15-minute rule for “the unit wasn’t reporting”, that thinning would have broken the line everywhere and read as constant coverage dropouts. The threshold now follows how far apart the points actually are, so a real gap still breaks the line and thinning doesn’t. The 24-hour chart is unchanged.
- ChangeThe two speed graphs on an asset page are titled — “24 Hour Speed Chart” and “7 Day Speed Chart”, rather than just naming the window.
v0.38.1
29 July 2026
- FixThe board no longer flags a shift change as something to look at. Several buses leaving one village within a few minutes of each other is how the division works — crews move between mine and camp at the same time, to different work fronts. Calling that a consolidation opportunity put a card on nearly every row of the busiest hour of the day and was wrong on all of them. A column headed “what to look at” that points at normal operations just teaches people to stop reading it. Two buses running the same trip is a different thing and is still raised.
v0.38.0
29 July 2026
- AddA “What to look at” column on the wet hire board — each row now carries the thing worth acting on, colour-coded: two buses running the same trip, several buses leaving together for different places, a hired-in bus working while our own sit idle, and the idle window itself. Today it finds NF1509 and NF537 running the same Gateway Village to Roy Hill trip three times over, six passengers on each — twelve between them.
- AddRecommendations say what was seen, never what it would save. Whether two buses can become one depends on whether the passengers fit, and the roster records passenger numbers on about a quarter of departures and seat counts nowhere at all. So a card reports the observation and, where both legs recorded passengers, the combined figure — and where they did not, it says “pax not recorded” rather than implying the two would fit.
- FixBuses are only called “hired in” when the register can support the claim. If not one bus on the roster appears on the asset register, the honest reading is that the register does not cover buses yet — not that all 46 are hired. Before this every row on the board was labelled hired in.
v0.37.2
29 July 2026
- AddClicking a bus number on the wet hire screens opens a card about that bus — type and depot, its live speed and location if it is a tracked asset, today’s driver and job, any sellable window, and a link through to the full asset page. Same behaviour as clicking a truck on the live map, which is the point: a vehicle number should do the same thing wherever you meet it.
- AddBuses that are hired in are marked as such. 14 of the 46 buses on this roster are not Northfleet assets — the GOW and RAW units — so there is no asset page and no live position for them. Their card says so instead of offering a link that opens on an empty page.
v0.37.1
29 July 2026
- FixA short idle window on the wet hire board had its label clipped — a departure marker sits over each end of the band, so a two-hour window had about half its width covered and printed “0.5h sellable — (2.0h gap)” as a clipped fragment wedged between the two blocks. Narrow windows now show as hatching alone and the detail stays in the tooltip, which is all a window that short warrants.
v0.37.0
29 July 2026
- AddWet Hire Operations — a new section for the Port Hedland bus division, built around the roster it is actually run on. The spreadsheet (126 days, 1,456 bus-days, 7,376 recorded departures) is imported and becomes two screens.
- AddWet Hire Board — the day, one row per bus, laid out across the hours instead of down a list. The transport schedule is lanes by day because a line-haul run happens on a day; a crew bus wastes its time inside one, so a day-per-column grid hides the only thing worth seeing. Each idle window is drawn as its own object: click it to sell it, or drag a charter onto it. Buses not out at all that day are one toggle away.
- AddWet Hire Opportunities — where the sellable bus time is and which buses it sits on. 5,978 hours of it across the roster, on buses that are already out and already crewed.
- FixThe import read 85 dates as departure times. A contract period written “30 Mar 2026 - Quote…” became a bus leaving at 20:26, which put phantom evening runs on the Telfer buses. Caught by looking at the board rather than at a total. The guard is on the month name in front of it, not on the hour — the roster has genuine departures as late as 22:45.
v0.36.0
29 July 2026
- AddThe dashboard’s live fleet can be filtered by depot and by business unit — two dropdowns above the map narrow both the map and the Fleet status list beside it to one depot, one business unit, or a combination of the two. The heading names what you are looking at, so a depot wall display says so, and the choice is remembered when you come back to the dashboard. The consignment figures along the top are unchanged: they count freight, not assets.
- AddAssets can be assigned to a business unit — Dry Hire, Wet Hire, Transport or Other, set on the asset register one row at a time or on a whole selection at once, alongside type and depot. Nothing Fleet Dynamics sends says which side of the business earns off a unit, so there is deliberately no suggestion feature for it as there is for types — a guess would be invention. An asset nobody has assigned yet is left out of every business-unit filter rather than being counted as “Other”: “Other” is an answer somebody chose, and “not said yet” is not the same thing. The register counts how many are still blank, and filters to them, so the list can be worked through. A re-import from Fleet Dynamics never touches an assignment made by hand.
- AddA filtered fleet says what it is leaving out — live positions only cover the asset types ticked track live, so a depot filter showing seven trucks is seven of however many that depot owns. The filter bar states the gap against the register whenever there is one, because on its own the seven reads as the depot’s whole fleet. An empty result explains itself too: with most of the register still ungrouped, “no matches” is usually “nothing has been assigned yet” rather than a depot with no trucks in it.
- ChangeThe sidebar has been tidied up — nothing moved and nothing was renamed, it just reads better. Each menu icon now sits in its own rounded tile, which evens out a set of symbols that were arriving at noticeably different weights and sizes; the four groups are separated by a hairline so the menu reads as four short sections rather than one long list; the current screen is a softer panel with a rounded orange marker instead of a hard block of blue; and the fold arrows are drawn as thin carets rather than solid triangles, which read as form controls. The alert dot on a folded group has room around it, and the wordmark’s underline is a blue-to-orange accent picked up from the logo above it.
v0.35.5
29 July 2026
- FixFour screens were each downloading about 8 MB of GPS history — the speed alerts, utilisation, events and assets pages all asked for a week of recorded positions for every tracked vehicle, then used nothing from them but the speed. Clicking through the system pulled roughly 33 MB; it is now about 12 MB, and no page shows anything different. The asset page still gets full positions, because it draws the vehicle’s route on a map.
- AddA pre-demo check that drives every screen against the real system — and reports what each one costs in time, requests and megabytes. The existing checks render every screen against sample data, offline, which cannot see this: a page can pass them and still be slow on the real fleet. It is strictly read-only, with three independent guards against writing anything back.
v0.35.4
29 July 2026
- FixSigning in took 15 seconds — every sign-in reads the whole database, and it was also reading months of stored GPS history and throwing it away. Position history moved into its own store recently and the read was told to stop skipping it, on the basis that there was none left to skip; in fact everything recorded before the move is still there, expiring slowly. Measured on the live system: 15.3 seconds to return 349 KB of actual data. The read skips it again, in every configuration.
- FixFleet movement — last 24 hours was still slow — the default view (51 prime movers) took 8.4 seconds and sometimes gave up entirely. The server was making two separate database requests per vehicle per day — 408 of them for one page. Measured live, the wait grew with the number of vehicles asked for rather than with the amount of data: 2 vehicles 1.2 s, 30 vehicles 1.9 s, 102 vehicles 5.8 s, and the first three of those returned no data at all. It now fetches them in batches, a handful of requests whatever the size of the fleet.
- ChangeMovement charts only download what they draw — a stored position carries latitude, longitude and heading as well as speed, and the speed charts use none of it. Asking for speed alone cuts the download by 60% (493 KB to 200 KB on the prime movers). The map trail and the distance figures on an asset page still get the full position.
- ChangeA history read only asks for the hours it covers — a 24-hour view was fetching both days in full and discarding what fell outside the window.
v0.35.3
29 July 2026
- Fix“Internal Server Error” on fleet movement — filtering to light vehicles (312 of them) asked the server for the recorded history of the entire fleet instead of just those, because the list of vehicles was longer than the page was willing to send. That whole-fleet read was slow before and became too slow to finish at all once round-the-clock recording started, so it failed outright. Long lists are now split into several smaller requests, and no screen asks for “everything” any more.
- FixA filter matching no vehicles could show another filter’s charts — asking for an empty list of vehicles fell through to fetching every tracked one. It now correctly returns nothing.
- ChangeEvery history read now names the vehicles it wants — which is the honest question anyway, since history is only ever recorded for vehicles ticked track live.
v0.35.2
29 July 2026
- AddSpeed over 110 km/h is drawn in red — on the fleet movement charts, the asset page, and the small 24-hour trace in a map popup. A wall of charts can now be scanned for the ones worth looking at instead of read one at a time. The threshold is marked with a faint dashed line so the colour change has something to be read against.
- ChangeThe colour changes where the line crosses, not at the nearest reading — the line is drawn once and a red copy is clipped to the band above the threshold, so a peak that just clips 110 shows a small red cap rather than reddening the whole climb.
v0.35.1
29 July 2026
- FixThe diesel figure is on every asset page, not only the ones with history — it sat inside the seven-day activity section, which collapses to a single line when an asset has no recorded movement. So on most assets the fuel report was simply absent, which looks like a missing feature rather than one waiting for data. It now always appears, in whichever of three states applies: a figure where there is distance; “no consumption rate for this type” for a trailer or dolly; or “no distance recorded yet” for a vehicle that has a rate but has not reported. The third case names the rate that will be used once distance arrives, so you can check it is right in advance.
- ChangeStill never a zero — an asset with no rate, or no recorded distance, reports no litres at all rather than 0 L. Nothing measured and nothing burned are different statements, and only one of them is true.
v0.35.0
29 July 2026
- ChangeBackend — position telemetry moved to a dedicated table — recorded position history and the daily rollups now live in their own DynamoDB table keyed by day, so the whole-fleet movement and utilisation reports and the main state read use windowed queries instead of scanning the entire table. This removes the timeout that would otherwise appear as the tracked fleet grows. Rolled out in stages behind a mode switch (legacy → dual → new) with an idempotent, resumable backfill, and defaults to the old behaviour so a deploy changes nothing until the mode is advanced.
v0.34.0
28 July 2026
- AddSafety incident & near-miss reporting — drivers can report an incident or near miss (near miss is now a first-class type and the default) with severity, notes, photos and GPS, synced offline-first. Dispatch gets a full review on the Events screen: filter incidents by status, severity and type, open one to see its photos and location on a map, and mark it resolved.
- AddReports — the fleet asset base — the Reports screen now shows fleet composition (assets by type and by depot), live-tracking coverage (how much of the register is swept every cycle versus rotated through the background sweep), and a 90-day asset-document expiry outlook with the soonest-expiring listed. These read from the asset register and document set, so they stay useful while the live GPS feed is empty; composition and coverage prompt to import the register when it’s empty.
- AddThe backend API is now secured behind a shared-token authorizer — every route is checked at the edge, so an anonymous request can no longer read or overwrite the operation’s data. It is default-on but fail-open until the token is stored, so it can be rolled out without an outage; media stays served by unguessable content-hash URL. This is a drive-by write barrier for the prototype, not per-user login — that remains the next step.
- ChangeSidebar navigation is now collapsible — the dispatcher menu groups its tools under expandable headings, with Dashboard pinned at the top. Fold a group away by tapping its heading; your open/closed choices are remembered between sessions, and the group containing the current screen always opens automatically. A collapsed group with an unread alert shows a red dot on its heading.
- FixAn asset’s movement trail no longer scans the whole history table — drawing a single asset’s week used to read the entire telemetry table and filter in the browser, which is what timed the asset page out. It now fetches just that asset’s rows by key.
v0.33.1
28 July 2026
- AddDiesel burn on each asset page — litres and dollars for the last seven days, alongside the distance they come from. It is modelled, not measured, and the page says so plainly. There is no fuel feed — no flow meter, no fuel-card import — so this is the recorded distance multiplied by an assumed litres-per-100km for the asset’s type. Both that rate and the diesel price are test figures you can edit on the asset register.
- AddLitres per 100km against each asset type — on the register, next to the two cost rates, with a diesel price per litre. Clearing either one removes it rather than storing a zero: an asset with no rate is reported as unmetered and no fuel is attributed to it, which is the right answer for a trailer or a dolly — it burns the prime mover’s diesel, and showing it as 0 L/100km would read as perfect economy rather than as not applicable. With no diesel price set, the litres still show and the cost reads as unknown, never as free.
- ChangeThe fuel figure says what it leaves out — if recording has gaps in the week, the distance and therefore the litres are a floor rather than a total, and it says so. Idling is excluded too and named: an engine running while stationary covers no distance, so fuel burned sitting still isn’t in the number. Inventing a second rate to cover it would have made the total look more complete than it is.
v0.33.0
28 July 2026
- AddContinuous position recording, ready to switch on — history is only written while a sweep is running, and a sweep runs when somebody has FleetView open, which is what was leaving 12 to 17 hours of every 24-hour chart empty. There is now a scheduled recorder that keeps it going overnight. It ships off: turning it on needs one AWS permission the deploy account does not have yet, and it costs money to run. Both are written up in the deployment notes.
- AddParked vehicles are recorded less often than moving ones — every couple of minutes while working, every thirteen while sitting still, and still often enough to draw an unbroken line. Most of the fleet is parked most of the time, so this avoids roughly two thirds of the readings. It compounds with the six-hour blocks below: fewer writes, each of them smaller. Movement is judged on position as well as speed, so a unit with a faulty speed reading is not treated as parked while it drives down the highway.
- ChangeEach scheduled run records repeatedly rather than once — one pass reaches about thirty vehicles and covering the tracked fleet takes about twenty passes, so firing once a minute would have left gaps longer than the chart tolerates. It also stands aside while somebody using the site is already refreshing, so the two never write over each other.
- ChangeRecording skips its database reads when nothing is due — deciding whether a vehicle needs a new reading meant fetching that day’s records first, and most vehicles on most passes need nothing. It now knows without asking.
v0.32.11
28 July 2026
- ChangeRecording a position costs about an eighth of what it did — every asset’s movement for a day was held in one record that was rewritten in full each time a position was added, and the database charges for a write by the size of the record afterwards, not by how much was added. So late in the day it cost as much to store one more point as to store the whole morning. Movement is now filed in six-hour blocks, which caps how much gets rewritten: the same data, roughly an eighth of the cost, and no risk of a busy asset outgrowing the record size limit. Nothing already recorded needed moving — the old records are read alongside the new ones — and the daily summaries are still worked out from the whole day, so a retry or a mid-day restart still cannot double a distance.
v0.32.10
28 July 2026
- FixFleet movement would have opened empty — the faster loading added moments ago asked for each vehicle by its Fleet Dynamics unit number, but recorded history is filed under the number plate. Against the live fleet that matched none of the 51 prime movers. It now asks by both, which is what every other part of the app already does.
- ChangeMeasured on the real fleet — the default view now loads in about 2.7 seconds and 344 KB, against 8 seconds and 3.6 MB before.
v0.32.9
28 July 2026
- AddFleet movement now explains its broken lines — a chart drawn on a 24-hour axis with seven hours of data in it looks like a broken truck. It now says how much of the window was actually recorded, and each vehicle carries its own “7.2h recorded · 4 gaps” caption. Positions are only recorded while the fleet is being swept, and the sweep runs when someone has FleetView open — so overnight there is usually nothing to draw.
- ChangeThe page loads about ten times faster — it was downloading the recorded history for all 573 vehicles in order to draw 51 of them: 3.6 MB and around ten seconds. It now asks for only the vehicles it is going to show, and the backend fetches those records directly instead of reading the whole table. A six-hour window used to cost the same as a seven-day one.
- ChangeCounts are stated against the register — “44 of 51 in the register, with history” rather than a bare number, so a vehicle that is grouped but silent is visible as a gap rather than simply absent.
v0.32.8
27 July 2026
- AddFleet movement filters by type and depot — and opens on the prime movers. Every tracked type gets a line on this page, and with the register grouped that is several hundred charts; the prime movers are the question you open it with, so anything wider is now a deliberate choice. Show whole fleet clears both.
- AddIt says what it is hiding — the count reads “6 shown of 8 with history” rather than just “6”, and a filter that matches nothing explains itself instead of going blank. “Not grouped” is a choice in the type list, since a vehicle can report telemetry while still being ungrouped and those are exactly the ones a type filter would hide.
v0.32.7
27 July 2026
- AddA 24-hour speed trace in the asset popup — clicking a truck on any of the maps now shows a small line of what its last day looked like, under the current speed: worked hard, one run out and back, or sat still, without leaving the map to find out. Same data and the same scale as the Fleet movement page, with the axes dropped because there isn’t room for them — the reading underneath gives the top speed for the day. A break in the line is missing data, usually the unit out of coverage, not a stop. An asset with nothing recorded yet says so rather than drawing a flat line that looks like a truck that never moved.
v0.32.6
27 July 2026
- FixVehicles outside the tracked types were dropping off the map — with 580 ticked to track live, the tracked list filled every refresh cycle and the remaining 609 vehicles got no calls at all, so after fifteen minutes they aged out and vanished. Live coverage was sliding, not climbing, while every figure on the feed looked healthy. A share of each cycle is now held for them.
- ChangeThe reserved share goes first in the cycle, not last — only the first few dozen calls of a refresh actually complete, so slots reserved at the end would never have been reached. Tracked vehicles still get around 80% of every cycle; the rest of the fleet is covered more slowly rather than never.
v0.32.5
27 July 2026
- FixThe rotation was still skipping most of the fleet — the previous release made it advance by what ran rather than by what it asked for, but the figure it used for “what ran” was itself wrong: it counted every vehicle in the batch except those explicitly passed over, and when a sweep is cut short the remainder are never reached at all, so they were counted as done. Measured on the live feed: it reported 120 refreshed when 26 calls had actually been made. It now counts the calls that were really started.
- ChangeThe “refreshed this cycle” figure on the live feed is now the true one, which is also what the rotation advances by.
v0.32.4
27 July 2026
- AddOperating cost rates are set on the live register — prime mover, rigid, trailer, bus, light vehicle, plant and crane. These are industry benchmarks, not Northfleet's accounts, put in so the fleet overview has something to work with; replace them with your own under Assets → Asset register → Types. 786 of the 890 grouped vehicles are now costed.
- Change“Not Used” and “3G - Old Units” are deliberately left unpriced — they describe a state, not a kind of vehicle, so guessing what they cost would be inventing money. Their 104 vehicles are excluded from every total and reported separately.
- FixHalf a rate is no longer treated as a whole one — a type with a daily rate but no per-kilometre rate silently costed its running as zero. It is now left uncosted and named on screen, so someone can finish setting it up. An explicit zero is still a real answer: plant genuinely isn't charged per kilometre.
- FixThe live feed now reports an oversized tracked list — the fields were being worked out and then dropped before the snapshot was stored, so a tracked list too long to refresh every cycle still looked like a healthy sweep.
v0.32.3
27 July 2026
- FixTicking more types to “track live” was making coverage worse, not better — the tracked set was swept in full every cycle with no upper bound. With 535 vehicles ticked, that left the rotating window no room at all and handed the sweep a batch far bigger than it had time for, so the same ~30 vehicles were refreshed every cycle and the other 505 — plus every untracked vehicle — were never refreshed again. A tracked set too large for one sweep now rotates as well, and a set that fits is still refreshed every cycle exactly as before.
- FixThe rotation was stepping over three quarters of the fleet — it moved on by the size of the window it asked for rather than by what actually came back in the time available, so the same 75% was skipped on every lap. It now advances by what really ran, which is what makes full coverage reachable at all.
- ChangeThe live feed says when the tracked list is too long to refresh every cycle — rather than leaving it to be inferred from vehicles that quietly stop updating.
- Change223 more vehicles grouped by type in the register — 178 trailers, 32 light vehicles, 11 buses and 2 rigids, read from their Fleet Dynamics descriptions. 299 remain ungrouped, 260 of which are recorded only as “Unallocated”.
v0.32.2
27 July 2026
- ChangeSuggest types now recognises more of the real register — checked against the actual 1,189 rather than against examples: commuters, Coasters and Yutongs are buses, Camrys and Sprinters are light vehicles, tautliners and fridges are trailers, and a description that just says “truck” is a rigid. It now groups 235 of the 534 ungrouped assets in one pass, up from 217.
- Fix“Drop deck” classified again — the register spells it both ways and a change to catch the truncated spelling silently stopped matching the full one. Found by running the classifier over the live register and diffing the result, not by a test.
- ChangeStill refuses to guess at 260 “Unallocated” units — along with service providers, hire arrangements, people's names and bare depot codes, all of which are in that field. They stay blank for someone to set by hand.
v0.32.1
27 July 2026
- AddEvery screen is now checked on every push — all 35 dispatcher screens plus the client and driver portals are opened in a real browser and asserted to render without errors. A screen that breaks fails quietly today: the app carries on and the only symptom is one page reading “Couldn't load this screen”. Nothing automated was opening a screen at all, so that could sit unnoticed until someone landed on it.
- AddIt also catches a screen that renders nothing — blank is a failure even when nothing was thrown — and covers stale links to records that no longer exist, plus an unknown address.
v0.32.0
27 July 2026
- AddFleet overview — the whole fleet on one page — reached from Assets and from Reports. Utilisation, distance and time over the limit, each against the previous 30 days so you see the direction of travel rather than a snapshot; then what the fleet costs; then the decisions waiting, each with the next step rather than just a number. It takes
?wall like the other monitor screens.
- AddOperating costs, so utilisation means something — each asset type carries a standing rate (what it costs to own per day — finance, rego, insurance, depreciation) and a running rate (fuel, tyres, maintenance per kilometre), both editable on the register. “8% utilisation” is a fact nobody acts on; the ownership cost carried against it is a decision. The starting rates are order-of-magnitude placeholders — set them to yours.
- AddWhat is being carried against no work — standing cost on the days a vehicle did not move, per vehicle and for the fleet, with the worst offenders listed.
- AddBy depot — utilisation, distance, over-limit rate and cost for the unit a manager is accountable for.
- ChangeIt will not invent money, and it says what it cannot see — an asset type with no rate set is excluded from every total and counted separately, never treated as free; a depot that is only partly costed says so on the line. And the coverage caveat is the first thing on the page in full size, not a footnote: live telemetry covers the vehicles ticked track live, and fleet-wide conclusions must not be read off a few dozen of 1,189.
v0.31.5
27 July 2026
- AddThe long run — 90-day utilisation — on the utilisation page, under the weekly figures. Seven days tells you whether a vehicle is busy this week; it cannot tell you whether you should still own it. Over a week a prime mover on one five-day job reads as idle, and a yard shunt that runs every morning reads as fully utilised. Each vehicle gets days-with-movement, total distance and a thirteen-week distance trend, worst first.
- AddIt refuses to have an opinion until it can back one — the daily summaries only start when the recorder does, so for the first fortnight every vehicle in the fleet looks unused. Nothing is called under-used until there are 14 days behind it; until then the figure is shown but marked “too early”. Calling a truck a disposal candidate on three days of data is the one mistake this page could make that matters.
- AddEmpty weeks are drawn, not skipped — in the trend, a week with no recorded data is a gap and a week the vehicle sat still is a flat bar. They mean different things, and a run of either is the finding.
v0.31.4
27 July 2026
- AddDid the conversation change anything? — a new panel on the speed alerts page comparing each vehicle's driving before the last conversation with the driving since. That is the point of recording one: without it the conversation is a box to tick, and nobody finds out whether it worked.
- AddMeasured as a rate, not a count — time over the limit per 1,000 km. A vehicle that simply did less work last week is not a vehicle that improved, and reporting it as one would credit a conversation that did nothing. No verdict is given at all until 200 km has been covered on each side: “clean for 40 km” is not evidence.
- AddSpeeding more since being spoken to is escalated on the Assets page — above the alert backlog. It is the one case where the next step is not another conversation.
- AddDaily summaries, kept for months — position history is large and expires after a week, which is fine for “where has it been today” and useless for “has anything changed since March”. Each day now also stores a small per-vehicle summary — distance, peak speed and a speed profile — that outlives the positions it was built from.
- ChangeLoading the app no longer downloads the position history — it was being read out of the database and thrown away on every sign-in and every sync. Small today because the recorder is new, but at 40 vehicles and a full week retained that is roughly 9 MB per load, growing with every vehicle tracked. Now it is never asked for, which is also what makes it safe to keep the daily summaries for months.
v0.31.3
27 July 2026
- AddSuggest types — group the register in one pass — Fleet Dynamics already describes each unit (“Freightliner CASCADIA (145T)”, “4T FLATBED”, “BUS - BCI”), so most of the 1,189 assets can be grouped from what they are called. It tells you what it found, broken down by type, and asks before it changes anything. This is what unblocks live tracking: only a grouped type can be ticked to track.
- AddIt never overwrites a grouping you have made — only a blank type is ever filled, and anything it isn't reasonably sure of is left blank for you. Roughly 280 units are described by their status rather than their type (“Tested 27/06/25 Faulty”, “Unallocated”, “SPARE”); those are left alone rather than guessed at. A wrong type is worse than no type — a misfiled prime mover drops out of live tracking without saying so.
v0.31.2
27 July 2026
- AddRepeat offenders are called out separately — a vehicle where the same conversation has already happened more than once needs a different response from a one-off, and a manager about to have that conversation a third time should know it. Shown above the alert list with how many conversations there have been and the worst reading among them.
- ChangeCounted on conversations held, not alerts raised — a pile of unactioned alerts is a backlog in someone's inbox, not evidence about a driver, and it never contributes. Nor does a dismissed alert: “unit fault, reading wrong” is a legitimate outcome and must never accumulate towards calling someone a repeat offender.
v0.31.0
27 July 2026
- AddAssets is now its own place under Operations — the page you manage the fleet from, in the sidebar beside Dispatch and Live Fleet. It leads with what needs a decision rather than with totals: unactioned speed alerts, vehicles overdue for service, anything that hasn't moved in days, and assets still not grouped. A count of 1189 assets tells you nothing; three trucks needing attention this morning tells you what to do.
- ChangeThe asset register moved out of Settings — grouping assets is configuration, but running the fleet is operations, and the register was buried under the wrong one. It now sits under Assets along with utilisation, movement and speed alerts.
- AddAn asset number is now a link, wherever it appears — in live arrivals, fleet status and the live fleet list. Click any vehicle and you land on its page.
- AddThe asset page now shows everything recorded about that vehicle — a week of speed against time, its utilisation, distance covered, every speed event with whether the conversation has happened, long idles, and any movement outside operating hours. Time the unit wasn't reporting is stated plainly and excluded rather than counted as idle.
v0.30.2
27 July 2026
- AddReal speed alerts now appear in the events log — alongside geofence arrivals and incidents, rather than only on their own page. A dispatcher shouldn't need to know which screen a particular kind of alert lives on.
- ChangeAn alert is only ever logged once — the history is re-read every time someone opens the page, so without this the log would collect another copy of every event on each visit.
- ChangeEach logged alert says the driver is inferred — the name shown comes from the roster, not from the tracking unit, and the entry says so plainly so nobody raises it with the wrong person.
- AddAssets in the dashboard’s Fleet status list are clickable — clicking one opens Live Fleet centred and zoomed on that truck with its details showing, instead of leaving you to find it in a list of twenty. Each row is a proper link, so it also works from the keyboard and can be opened in a new tab. The vehicle list on Live Fleet itself can now be reached by keyboard too, which it couldn’t before.
- FixThe conflicts card always has its two example conflicts — the sample roster put a driver on a job while they were away, and a truck on a job while it was in the workshop, so the conflicts card had something real to show. Both sat on a fixed day relative to today, which lands on a weekend depending on the day of the week — and nobody is rostered at the weekend, so the conflict quietly disappeared. There were two midweek, one on a Thursday and none at all on a Friday. Leave and servicing now fall on working days, which is where they belong anyway.
v0.30.1
27 July 2026
- AddUtilisation by depot — the unit a depot manager is actually accountable for: assets, how many are under-used, utilisation, distance, and how many driver conversations are still outstanding. Ordered by outstanding conversations first, then by lowest utilisation, so the depot needing attention is at the top. Assets with no depot set are shown as such rather than quietly left out of the totals — with most of the register still ungrouped, dropping them would make every depot figure wrong.
- AddLong idles and after-hours movement — two costs that never show on a live map. Engines left idling more than half an hour are totalled per asset, and any movement outside operating hours is counted. Night line haul is normal in this business so it isn't treated as an accusation, but unauthorised use looks exactly like this and nothing else in the system would surface it.
- ChangeA dropout is never counted as idling — if the unit stops reporting, that time is excluded rather than recorded as a stationary engine. Inventing hours of waste that never happened would be worse than reporting none.
v0.30.0
27 July 2026
- AddAsset utilisation — which vehicles are earning their keep — for every tracked asset over the last week: hours moving, hours idle, distance covered, peak speed and a utilisation percentage, sorted least-used first. Anything that moved less than a tenth of its measured time is flagged, and anything that hasn't moved for days is called out by name. This is the list to work from when deciding what to redeploy, hire out or sell.
- ChangeTime we didn't measure is never counted as idle — where a unit drops out of coverage those hours are reported separately as unknown. Folding them into idle would make a working truck look under-used, and that is a number someone might act on commercially.
- AddSpeed alerts, built around the conversation rather than the alarm — recorded speeds over the limit plus a 5 km/h tolerance, with consecutive readings grouped into a single event, because a truck eight over for twenty minutes is one conversation with a driver, not ten alerts. Each one carries an outcome: who the depot manager spoke to, when, and what was said. The page is organised around what is still outstanding, so it works as a to-do list rather than a wall of noise.
- ChangeThe system never guesses who was driving — position history belongs to the vehicle, not a person. The manager records who they actually spoke to. Pinning a speeding event on the wrong driver would be worse than pinning it on nobody.
- AddSpeed limits can be set per asset type — a bus or a light vehicle is not a road train, and each type can carry its own limit for alerts to be measured against.
v0.29.29
27 July 2026
- AddFleet movement — the last 24 hours at a glance — a new page under the asset register showing speed against time for every tracked vehicle: 0 to 120 km/h up the side, the hour of the day along the bottom. One small chart per truck rather than every line on top of each other, so you can actually read what an individual vehicle did. Busiest first, with its peak speed and how much of the day it spent moving, and each name links through to that asset's own page.
- ChangeA gap in the data is shown as a gap — where a vehicle drops out of coverage the line breaks, rather than being drawn straight across at some invented average speed that never happened.
v0.29.28
27 July 2026
- FixPosition history was recording nothing at all — a vehicle answers to two different numbers: the register tracks it by the GPS provider's unit number, while its position comes back labelled with its plate. The recorder only checked one of them, so nothing ever matched and not a single position was stored, on a feed reporting 106 vehicles. Caught by checking the live system after deploying rather than trusting the release. Either number now matches.
v0.29.27
27 July 2026
- AddThe system now keeps a record of where vehicles have been — until now it only ever knew where each one was at that moment, overwritten every fifteen seconds, so “where has this truck been today” could not be answered at all. Positions are now kept for seven days and expire on their own. This costs the GPS provider nothing extra: it stores what has already been fetched, rather than asking again.
- AddHistory is kept for the vehicles you track live — the prime movers ticked in the asset register. They are checked every cycle, so their history is detailed enough to be worth drawing; the rest of the fleet is checked in rotation, minutes or hours apart, which would make a misleading line rather than a useful one.
- AddA way to read that history back, thinned to a sensible number of points for whatever period is asked for, so a day of movement for the whole prime mover fleet comes back in one quick request instead of megabytes.
- AddSee where a vehicle has been, and where it's heading — the asset page now shows a map with the last 24 hours of movement drawn as a line. Where the vehicle is moving, a dashed line shows where it would reach in half an hour on its current heading; it is labelled a projection, not a route or an arrival time, because that is all it is. Where the vehicle has a job allocated, the booked destination is named alongside it — that part is fact rather than arithmetic.
- ChangeAn asset with no history yet says so — recording only began when it was switched on, and only covers vehicles ticked to track live, so a blank map is expected at first. The page explains that instead of looking broken.
- ChangeRecording can never cost you a position — it runs after the live snapshot is safely stored, and if it fails the snapshot is untouched. Days are counted in local time, not UTC, so a morning's driving isn't split in half at 8am.
v0.29.26
27 July 2026
- AddVehicles on the map are clickable — tapping one shows its speed, whether it is moving, its asset number, type, driver and nearest address. The same panel now appears on both the dashboard map and the full Live Fleet map, so the two can't drift apart.
- AddAn asset page behind every vehicle — the asset number in that panel opens a page for the vehicle: what it is, where it is right now, its service history, and the jobs and consignments it has carried. Reachable from either map.
- AddService history and kilometres until the next service — measured against the odometer the GPS unit actually reports rather than estimated from dates, with an amber warning as it approaches and a red one once it is overdue. Where there is no service on record or no odometer reading, it says so instead of inventing a figure.
- AddSortable columns in the asset register — click any heading to sort, click again to reverse. Unit numbers sort numerically rather than as text, and blanks always sort to the bottom whichever direction you choose.
- ChangeAssets are matched across three different numbering schemes — the GPS provider calls a truck “NF1258”, the operational fleet list calls it “NF-104”, and a job references the second. These are now compared consistently. Where an asset genuinely has no operational record the page says why, rather than showing an empty list that reads as “this truck has never worked”.
v0.29.25
27 July 2026
- FixGrouping an asset could quietly change a different one — rows in the asset register were identified by their plate, and in the real register the plate field doubles as a status note: 87 assets read “3G”, 61 “SPARE”, 41 “U/S” and 72 are blank. Setting a type on one of those rows changed the first asset with the same plate instead of the one clicked, ticking one selected all of them, and a bulk assign applied to every one. Nothing on screen showed it. Rows now use the GPS provider's own unit number, which is unique.
- AddThe unit number is now shown, and searchable — hundreds of assets have no plate and share the same description, so there was no way to tell one row from another. Each row now carries its unit number, and the search box matches on it.
- AddYou can see the whole register — the list stopped at the first 200 of 1189, with no way to reach the rest. Show more and Show all now sit under the table. It still opens at 200 for speed, since every row carries two dropdowns.
- ChangeFleet status lists the moving trucks first — ordered by speed, so whatever is on the road is at the top instead of buried among the parked assets. Stationary vehicles keep a steady order between refreshes rather than reshuffling.
- AddAutomatic checks for the register (18) — that editing one row changes only that asset, that a blank-plate row is individually editable, and that the whole list can be reached. Confirmed they catch the original fault.
v0.29.24
27 July 2026
- FixLive vehicle tracking — we weren't staying signed in to the GPS provider — their system keeps you signed in across requests, the way a website does once you log in. We were signing in and then dropping that immediately, so every request for a vehicle's position arrived as if from a stranger. Their system answered with nothing at all — no error, no warning — for every one of the 1189 assets, which looked exactly like “these vehicles have no tracking fitted”. The sign-in is now held and sent with every request, and if it ever lapses the system notices and signs in again by itself.
- ChangeThis was very nearly reported to the provider as their fault — their own test page returns the same empty answer, which read as proof. It isn't: that page has the same problem, because it asks for a position without signing in first. Recorded in the technical notes, because the evidence pointed firmly the wrong way.
- AddAutomatic checks for staying signed in (
node backend/tests-fd-session.js) — that the sign-in is carried on every request, that it never appears in any output or log, that a lapsed sign-in recovers on its own, and that a refused sign-in degrades quietly rather than breaking. Confirmed the checks catch the original fault. Added to every build and to the deployment gate.
v0.29.23
27 July 2026
- AddThe version number opens the changelog — on the sign-in screen, in the client portal footer and at the bottom of the driver app, the same way the dispatcher’s sidebar already did. It opens in a new tab, so you don’t lose your place. On the driver app the changelog sits outside the offline bundle, so that one needs signal.
- FixThe conflicts card always has its two demo clashes — the sample roster is meant to show one driver rostered while on leave and one truck rostered while in the workshop. They were pinned to fixed positions on the board rather than to the leave and service days themselves, so as the calendar moved they drifted onto whichever driver and truck happened to be there — some days landing on a rest day and disappearing altogether, and today showing two driver clashes and no truck clash. Sample data only; nothing a dispatcher enters was affected.
v0.29.22
26 July 2026
- AddEvery GPS position opens on a map — coordinates used to be text you had to copy out and paste somewhere to find out where a truck, a delivery or an incident actually was. Now each one is a link that opens that spot in Google Maps in a new tab: the time and GPS stamps on a consignment’s job flow, the proof-of-pickup and proof-of-delivery stamps, the location column and detail on the events log, open incidents, the load-check submissions, and the live stamp on the signature pad — so a position can be checked before it’s committed to the POD. Clicking a position inside an event row opens the map, not the event, and the links are reachable by keyboard. The driver app is deliberately left alone — a driver on a run should not be sent out into another app, and their screens already have their own Navigate button.
v0.29.21
26 July 2026
- FixThe driver’s app keeps the last run it was sent, and opens on it — it read the run from the office every time it started, but never wrote that copy down. What it kept on the phone was only whatever the driver themselves had last changed, so opening the app in a dead spot showed a days-old sheet, or on a new phone the sample roster — and with signal, that same wrong sheet was what you saw for the first second until the real one arrived. Every successful sync is now saved on the phone, so the app opens on the last run it was given, immediately, whether there is signal or not.
- AddA Refresh button on the run sheet — next to Today’s run, with a line under the driver’s name saying when the sheet was last updated. Out of range it says “No signal” and keeps showing the last run rather than pretending; back in range, one tap pulls whatever the office has changed without closing the app. Anything the driver has captured but not yet sent goes out first, so a refresh can never overwrite a time or a POD that hasn’t reached the office.
- FixAn app that was only ever looked at no longer counts as having unsent changes — simply opening it marked the phone’s copy as unsynced, which on the next start had it re-applied over the database and sent back. A screen nobody touched could quietly undo a dispatcher’s edit.
v0.29.20
26 July 2026
- FixThe driver’s run opens on the right day’s work — the app draws the sheet the moment you sign in, before it has finished reading from the database, and it was never redrawing when the data arrived. So it showed whatever was last saved on the phone — the wrong number of stops, the wrong jobs — and only corrected itself when you tapped Today or Tomorrow, because that forced it to redraw. It now redraws as soon as the data lands, so the first thing a driver sees is the real run. The dispatcher’s screens have always done this; the driver app had one character wrong.
v0.29.19
26 July 2026
- FixDragging a job to another day now moves it for the driver too — the run moved on the board and the job behind it stayed where it was, so a load dragged from Monday onto today appeared on the dispatcher’s schedule and nowhere else: the driver’s app still had it on Monday and showed nothing for today. The job now moves with the cell — day, driver, truck and the day label — whether it is dragged between days, dragged between drivers, or scheduled from the unscheduled list.
- FixScheduling a connote from the unscheduled list no longer risks a duplicate row — the new run wasn’t linked back to its job, so the next load treated it as work with no job behind it and created a second one.
- FixDragging one leg of a relay moves that leg — the job was looked up by connote, which for a multi-leg run always found the first leg, so moving leg 2 quietly re-dated leg 1. Rostered movements with no connote weren’t updated at all.
v0.29.18
26 July 2026
- FixThe driver’s run sheet reads down the day, like the board does — it was ordered by status, so an assigned afternoon job sat above a delivered morning one and the first card showed a time the schedule had further down. Every driver with more than one job saw a different order from their own line on the board; one run read 15:00, 09:00, 14:00, 05:00, 10:00. It now runs in start-time order, and the highlighted “next” job is the earliest one still to do. The times themselves were always the same — it was only the order.
- AddPreloads and backloads now show on the run sheet — they are on the dispatcher’s board but aren’t jobs, so the driver doing them never saw them: the board said “04:00 Preload” and the sheet opened at 07:00 with no mention of it. They appear in the day’s order as read-only context — time, route and what it is — with nothing to tap, and they aren’t counted as stops.
- FixThe in-cab Drive screen picks the earliest job, not an arbitrary one — with two jobs at the same status it fell back to whichever came first in the list, so it could point at the afternoon load while the morning one was still to run.
v0.29.17
26 July 2026
- AddA way to put a current roster back into the live site — the demo roster is built around today every time the app loads, but the deployed site doesn’t use it: it shows the roster saved in the database, which stays on the four-week window it was generated for. So it looks right for about a fortnight and is then empty, with nothing to fix it. backend/refresh-roster.js reports what is stored against what a fresh roster would give, and writes the fresh one on request. It touches only the schedule and the jobs — consignments, proofs of delivery, checks and invoices are left exactly as they were — and it declines to run while the stored roster still has a fortnight of work in it.
v0.29.16
26 July 2026
- FixThe driver’s app shows tomorrow’s run again — the board and the driver’s phone disagreed about tomorrow: the dispatcher could see a full line of work against a driver while that driver’s app said there was nothing on. It affected 19 of 40 driver-days and hid 49 runs. A run and the job behind it are created together, but only ever for today and tomorrow — so once the saved plan was even a day old, the runs that had since become “tomorrow” had never had a job made for them, and nothing went back to create one. The app now checks the board for work with no job behind it and fills the gap, every time it loads and after every sync.
v0.29.15
26 July 2026
- AddEvery run says how long it takes — the board, the dispatch cards, Driver Runs and the driver’s own job card now read 07:00–14:00 · 7h rather than leaving you to do the subtraction on every row. That subtraction is what you are doing when you scan the board for who is free. An overnight leg counts through midnight, so Newman to Perth reads 23h 30m rather than a negative.
- ChangeTimes are on a 24-hour clock everywhere — the header clock, event and incident stamps, quote correspondence, POD and geofence times all showed 4:34 am. Every docket and work diary in the yard runs on a 24-hour clock, so the app now does too: 04:34. Money and weights are unaffected.
v0.29.14
26 July 2026
- FixThe driver app and the schedule agree on the live site too — the last release lined the two up for freshly generated data, but not for the jobs already saved in the database, which is what the deployed site actually shows. Those were saved before a job carried a date, so every one of them read as “today” on the driver’s sheet while the board still had the same runs on the day they were booked for — open Wayne Carter in the schedule and in the driver app and you were looking at two different days. A saved job now takes its date from the board, and the two are linked, so all twenty drivers agree on both days. Nothing needs re-entering: the dates are worked out from what is already there, the first time each app loads.
v0.29.13
26 July 2026
- FixThe driver’s run sheet opens on the day their run is actually on — it opened hard on today, which looked right until a rest day: nobody is rostered on a Sunday, so every driver’s app was blank and the in-cab Drive screen had no stop to show, when what a driver wants on a Sunday evening is the Monday 4am run. It now opens on today when there is work on it and tomorrow when there isn’t. Picking a day on the switch still pins that day.
- ChangeThe Drive screen looks ahead rather than going blank — the in-cab display answers “what am I heading for”, so when the day on screen has nothing active it shows the next day that does, marked NEXT with the day named. Nothing on a later day’s stop can be actioned — no time capture, no signature — because stamping a time or signing for tomorrow’s load would be a false record; navigation still works, so a driver can see where they are going.
v0.29.12
26 July 2026
- FixThe driver’s run sheet now matches the schedule board — a driver’s app showed a set of jobs that had nothing to do with what the schedule had them doing, because the two were built separately: the board was full of runs with no job behind them, the jobs carried no date at all, and not one of them was linked to a run on the board. A job now carries the day it is for and is created together with the run it belongs to, so the sheet a driver opens is the row dispatch is looking at.
- AddToday / Tomorrow on the driver’s run sheet — the sheet used to show every job a driver had, whatever day it was for, so a driver looking at their run couldn’t tell what was theirs today. It now shows one day at a time with a switch across the top and the count on each button, and the heading says which day is on screen.
- FixRostered rest is never scheduled over — when a job is placed onto the board it now steps past a Sunday, a fatigue or mandatory rest block, driver leave and truck maintenance to the next day the driver and truck are both actually available, rather than putting work on top of a rest day.
v0.29.11
26 July 2026
- ChangeA check the office rejects holds the load too — rejecting an L&D check now stops the driver departing, the same as answering NO to a declaration does. Before, the sign-off was recorded and shown in the office but the driver's app took no notice of it, so a rejected check still released the truck. The driver sees the reason the office gave and the same one-tap call, and the step asks for a re-check. A check still waiting on review is not held — a clean check releases the load as it always has.
- FixA re-check that still finds a fault blocks the departure again — it is now the newest load check that decides, not whether any earlier one was clear. Before, once a check had come back clear, a later re-check that found a new fault no longer held the load: the driver's job card went back to reading “submitted” and the departure time was free to record, even while the office's own screen was counting that job as an open non-conformance. The two now agree, and the load stays put until a re-check comes back clear.
- AddThe stop stays on the docket, with the call — the STOP panel used to exist only while the form was open, so once it closed the driver had a held load and nothing telling them why or who to ring. The docket now shows it on the blocked step: the declaration that failed and which version it was answered on, the manager advice already recorded (or a prompt to call if none has been), and a full-width ☎ Call operations button with the number on it — one tap to dial, or read it out if they're on another phone. The step's own button reads Re-check the load, and the whole panel clears the moment a re-check comes back clean.
- ChangeThe STOP rule now lives in one place — a load check with an open non-conformance holds the departure until it's rectified and re-checked. The driver's docket and the office's Checks screen were each applying that rule from their own code, and the shared function they were both meant to use had a weaker version of it that would have let a stopped load through. Nothing was wrong on screen — the shared function had no callers — but both now use it, so the two can't drift apart.
- FixA record the office can't save no longer strands the others — when one consignment is too large to store, everything else in that save still goes through and the driver gets the red “call the office” message naming the record. If some of the rest were also held up for a reason that would clear on its own, they were being abandoned along with it. Those are now retried until they land, while the record that needs attention is still reported.
- FixThe daily checks now roll over at midnight, not 8am — a pre-start or fitness-for-work record was filed against the UTC date, and WA is eight hours ahead of that, so the app's idea of “today” changed at 8 o'clock in the morning. A check done at 5:30am was recorded against the previous day and the app asked for a second one at 8am, mid-shift; worse, a check done on Monday afternoon still counted as Tuesday's for anyone starting before 8am, so nothing asked them for that day's pre-start at all. Checks already in the system read back on their correct local day — nothing needs redoing.
- FixA time recorded out of signal is no longer lost when the app restarts — work saved on the phone but not yet sent to the office was being overwritten by the office's older copy the next time the app opened, and the sync pill then showed a green Synced. The app now recognises that it is still holding unsent work, keeps it, and sends it as soon as it has read the database.
- FixA change made while a save is in progress is no longer stranded — tapping two times a moment apart could leave the second one sitting on the device, again under a green “Synced”, until some later change happened to carry it along. Each save is now tracked separately, so the newer one goes out on its own.
- FixYou can close a pre-start again — on an installed phone the ✕ at the top of a check was drawn up behind the clock and battery, where the phone keeps the tap for itself, so the button was visible but dead and rotating to landscape and back was the only way out. The header of a full-screen form now starts below the notch, and the ✕ is a full-size 44px target that matches the back arrow.
- FixSame for the other pop-ups — the docket, POD, messages and incident sheets open to at most nine tenths of the screen, which on a smaller phone was still far enough up to put their close button under the clock. They now always stop clear of it.
v0.29.10
26 July 2026
- ChangeThe sign-in box sits to the right — so the bus and truck in the photo aren’t hidden behind it. On a tablet or phone, where the box takes up most of the width anyway, it stays centred.
- FixThe sign-in box was cut off on a phone — it stayed a fixed width even when the screen was narrower, so on a 360–390px phone the right-hand edge of the box, and the right side of the operator and password fields, sat off screen. It now fits whatever width the phone has.
- ChangeSign-in photo swapped for a version without the logo printed on it — the previous file carried the Northfleet logo in its top-left corner, which the screen had to crop into on a wide window. The new photo has no logo of its own, so the crop is clean at any window shape and the only logo on the screen is the one on the sign-in card. Slightly smaller file too, so the screen loads a touch faster.
v0.29.9
26 July 2026
- AddThe sign-in screen now shows the fleet — the Northfleet photo sits behind the sign-in card, with a wash over it so the card and its text stay easy to read whatever is in the picture. On a phone, where the photo crops to a narrow strip, the wash is stronger so the card still reads cleanly. If the image is ever missing the screen falls back to the old brand gradient rather than breaking.
- AddThe build number is on the sign-in screen — shown across the foot, so anyone reporting a problem can read off which build they are on before they even log in. It comes from the same single source as the sidebar, so the two can’t disagree.
- FixSign-in was unreachable on a short window — the sign-in card is taller than a small laptop screen or a phone held sideways, and the screen it sits on couldn’t scroll, so the Sign in button and the portal QR codes were simply off the bottom with no way to reach them. The screen now scrolls when the card doesn’t fit.
v0.29.8
26 July 2026
- AddThe deploy now checks the site it just published — it used to finish at “invalidation created”, which says nothing about what the site actually serves: a sync that quietly missed a file and an invalidation that didn’t cover it both look exactly like success, so the only way to know a release had really landed was for someone to open the site and read the version off the sidebar. The deploy now fetches the live site and fails if it isn’t serving the build that was just pushed — the app version, the driver service worker’s version (a stale one leaves drivers on the old offline copy however many times they reload), and that the published settings actually point at the database rather than leaving the site saving to nowhere. It waits for the cache to clear before deciding, so a slow edge doesn’t read as a failure.
v0.29.7
26 July 2026
- ChangeA full day's work on the dispatch board — the demo board carried 31 jobs across a twenty-truck fleet, which left five drivers with nothing on them and every column looking thin. It now runs to 56 jobs with all four columns populated and every driver carrying work.
- AddRelay line haul you can actually see working — there was a single two-leg example. There are now four relay runs, including a three-leg chain with a changeover already recorded, a leg nobody has been put on yet sitting in the unassigned column, and a trailer taken over without the hand-over being recorded — the out-of-signal case, which is allowed but reported. Those are the situations the board exists to catch, and they had almost no data behind them.
v0.29.6
26 July 2026
- ChangeThe asset register has moved to its own page — with 1,189 assets it filled the Settings page and pushed everything below it out of reach. Settings now carries a short summary — how many assets are on the account, how many are tracked live and which types those are, and how many are still without a type or depot — with Open asset register beside it. The register itself is unchanged: same import, grouping, search, filters and bulk assign. Settings stays highlighted in the menu while you’re on it, and there’s a link back.
- FixA black bar sat at the bottom of every screen — the strip that slides up to confirm an action (“Settings saved”) was only being pushed down by a proportion of its own height, which was never far enough to clear the bottom of the window. Roughly 20 pixels of it stayed parked above the taskbar at all times. It now clears the window completely and is hidden outright when there is nothing to say.
v0.29.5
26 July 2026
- ChangeThe demo schedule follows the calendar — the sample roster was written against a fixed week in July, so once that week passed the board opened empty, which looks broken rather than quiet. It now fills a four-week window around whatever today is: preloads, runs with real routes and goods, backloads, fatigue and mandatory rest days, leave and RDOs. The hand-written week keeps its detail, and the same day always produces the same board.
- FixBackload opportunities only list the days you're looking at — the empty-legs panel scanned the entire roster, so with a month of work loaded it ran to dozens of rows and pushed the grid off the screen. It now covers the days on screen, which is the only place you can act on one anyway.
v0.29.4
26 July 2026
- ChangeChecks & Forms is now a heading with a screen for each kind of check — it was one screen listing everything mixed together. The sidebar now reads Checks & Forms as a heading with Fitness for work, Prestarts and Load and Dimensions under it, each showing only its own checks, with its own figures and its own badge. A fitter chasing trailer defects and someone signing off loads are doing different jobs and no longer have to share a list. Existing links to the old screen still land on Load and Dimensions.
- FixMenu badges showed as empty red dots when there was nothing to report — a badge with a count of zero is meant to disappear, but a styling rule was overriding that, so several menu items sat there with a permanent red dot that looked like an unread alert. Badges now appear only when there is something in them.
v0.29.3
25 July 2026
- AddOne filterable list of every L&D check, including the ones not done yet — Checks & Forms now opens with L&D check status: one row per job that owes a check, in one of five states — not started, incomplete, waiting review, approved, non-conformance. Each state is a one-click filter showing a live count, and you can search by connote, customer or driver. Worst first, so anything stopping a truck is at the top. This replaces the separate “awaiting a check” card — jobs with no check are now in the same list as everything else instead of off to one side.
- AddThe office can now sign a check off — open one from the list to see exactly what the driver declared, the load photos and where it was signed, then approve it or reject it with a note saying what needs correcting. Both record who decided and when; a rejection goes to the Events log alongside the driver-declared stops, and shows on the job itself. Before deciding you see what’s worth weighing — a NO answer, an unanswered question, no load photos, or an oversize load with no permit attached. A decision made in error can be reopened. Re-doing a check still files a new version and leaves the original exactly as the driver gave it.
- FixThe figures at the top of Checks & Forms were unstyled and disagreed with each other — the four tiles were using style names that don’t exist, so they rendered as plain stacked text, and “Outstanding” counted jobs with no clean check (which includes the flagged and unfinished ones) so it never matched the list beneath it. The tiles now look like every other screen’s and read from the same counts as the filters.
v0.29.2
25 July 2026
- AddPrestarts take a quad road train — the trailers and dollies list now goes up to 7 units (4 trailers + 3 dollies), the largest combination we run. The paper form stopped at 5. Add or remove units as you hook up; a bobtailing truck adds none.
- ChangeDaily checks are in the order you do them — fitness for work first, then the truck prestart, then the trailer check. It's the one that can stop your shift before anything else happens, and it now matches the order the warnings appear in on the run screen.
v0.29.0
25 July 2026
- AddThe real truck prestart is now in the driver app — the full current sheet (form #256, all depots V3): fitness for work with a signature, the certification, odometer and service details, dash cam, every mechanical check, the mandatory items list, the trailers and dollies in the combination, the four daily photos and a final signature. It replaces the short placeholder list that was there, and it is submitted and saved to the database against your name, time, truck and GPS — not a tick that disappears when you close the app.
- AddTrailer prestart — form #257, for each time you hook onto a trailer that wasn't in that morning's check. Add each trailer or dolly in the combination and it asks the hub meter, ring feeder, spare, lights and tyres for each one.
- AddQuick fitness-for-work record — form #229, for when the office isn't open or you start before pre-start: fit for work with 7 hours' continuous rest, a photo of the breath test result held next to the date, and a signature. Answering no stops the shift and asks who you reported it to.
- AddWarnings for what you still owe — the run screen already warned about an outstanding pre-start; there is now one for the fitness-for-work record too, and each is a shortcut straight into that check. Both clear as soon as the check is filed.
- Change“Requires attention” is a defect report, not a dead end — a prestart fault is sent to dispatch and the check still files, so the driver isn't stuck. The review screen lists exactly what will be reported before you submit. A fault on the second trailer is reported as being on the second trailer.
- ChangeForms can now ask three new things — signatures, tick-every-item lists, and repeating groups (one set of questions per trailer or dolly). Any future form can use them without new code, which is what let these three sheets be added as data.
v0.28.0
25 July 2026
- FixThe schedule shows the real today again — the board was pinned to a fixed week in July with Wednesday marked as “today”, so it never advanced and the highlight was on the wrong day for anyone who looked at it. It now runs from yesterday, through today, to a week ahead, with today highlighted and yesterday greyed back so it doesn't read as something you can still plan into.
- AddLook ahead as far as you need — Next week jumps to the coming Sunday–Saturday week and can be pressed again and again to keep going out; Prev week goes back the same way, and Today returns to the default view. The date range on screen is spelled out next to the buttons, and when you've paged away from today it says so.
- ChangeNarrower depot column on the schedule — it only ever holds a site code (PHE, KTA, ZNE, HAZ), so it no longer takes the width of a full name. The space goes to the day columns, where the work is.
- ChangeA scheduled job now belongs to a date, not a column — underneath, each cell was tied to its position on screen, which is why the week could never move. Work is now filed against the actual day, so a job planned three weeks out stays on that day, and future weeks are genuinely empty instead of repeating this week's runs. Existing rosters keep exactly the dates they already had.
v0.27.8
25 July 2026
- AddRelay line haul — one load, several drivers — a long run like Port Hedland to Perth can now be booked as a relay: one driver takes it as far as Newman, hands the trailer over, another takes it through to Perth. Each leg gets its own prime mover, driver and shift, and the connote screen shows the whole chain with the changeover between the legs, so the office can see at a glance who has the load right now.
- AddDrivers only see their own leg — the run sheet says which leg of the relay a driver is on, who they take the trailer from and who they hand it to, and the docket now asks only for the steps that are actually theirs: the driver who loads captures the pickup and the load check, the driver who finishes captures the delivery and the POD. Handing the trailer over and taking it on are each recorded with the time and location.
- AddThe office is told when a changeover doesn't add up — if a driver records taking a trailer that nobody recorded handing over, the connote says so and asks the office to confirm the drop. Drivers are never blocked by it: out of range the other driver's phone may not have synced yet, and the trailer is in front of them either way.
v0.27.7
25 July 2026
- AddLoad & Dimension checks, done on the phone at the trailer — the L&D check is now part of the driver app, completed after loading and before departure. The compliance declarations, the trailer, the con note and the four load photos, one section per screen with buttons sized for a driver in gloves. The trailer and con note come pre-filled, a part-finished check survives the app being closed, and the pickup departure time stays locked until the check is submitted — the load can't be recorded as leaving until it has been cleared.
- AddAnswering NO stops the job properly — the paper form said "STOP and call your line manager", which is easy to skip. Answering NO to any declaration now shows the stop notice with a one-tap call to operations, requires the driver to record who they spoke to and what they were told, raises an alert to dispatch, and keeps the departure locked until the load is rectified and re-checked. Both the failed check and the corrected one are kept — the history of what was declared is the record.
- AddEvery check visible in the office — a new L&D Checks screen lists everything drivers have submitted with the declarations, the load photos, who signed it, when, and where by GPS. Filter to open non-conformances, and the menu badge counts loads that legally cannot move. Each check also shows on its own consignment alongside the times and POD.
- AddHigher-quality load photos — load and restraint photos are evidence for damage claims, so they are captured at a much larger size than a POD thumbnail, with the guidance about what to photograph shown where the photos are actually taken.
- ChangeForms are now configuration, not code — the L&D form is defined as data, so a customer with their own requirements gets their own version (BHP's site-entry variant is included as a worked example) and new forms can be added without touching either app. Built this way because more forms are coming.
v0.27.6
25 July 2026
- FixThe client portal can be used without a mouse — the two menu items and every shipment card were clickable but couldn't be reached by keyboard at all, which on the customer-facing app is the worst place for it. Shipment cards are now proper links, so Tab reaches them, Enter opens them, and you can middle-click one to open a shipment in a new tab. The “back to your shipments” link works the same way. There's also a clear yellow outline showing where you are, which the browser's faint default never managed against the dark blue bar.
- FixThe phone menu behaves like a menu — it now closes when you tap the page behind it or press Escape, and the menu button tells screen readers whether it's open. The panel used to be positioned by a fixed measurement that only lined up when the menu had exactly two items, and it sat on top of the page either side of that; it now pushes the page down cleanly and its rows are a comfortable size for a thumb.
v0.27.5
25 July 2026
- ChangeThe driver app no longer presents itself as a work diary — the Diary tab is now Hours & breaks, and it says on the screen that it is an unofficial guide based on the times recorded here, not an approved work diary, and that drivers must keep their own. A legal work diary has to be government-approved; this app is not one, and a driver who relied on it as their record would have been carrying nothing valid. The hours, break countdown and warnings are all unchanged — only what the screen claims to be.
- AddReady to plug in a certified work diary — when an approved provider (such as Logmaster, or the one built into MT Data) is connected, the app shows that provider's hours instead of its own figures, names it on screen as the diary of record, and flags the numbers if it hasn't heard from it recently. Nothing else in the app changes when that is switched on.
- FixThe driver selector no longer gets pushed off the side of the screen — for vehicles with a long description, the vehicle line stretched the top corner of the header wider than the phone, taking the driver name and selector off-screen with it. It now shortens with an ellipsis as it should.
v0.27.4
25 July 2026
- AddPhotos and signatures are now filed away by the server, whatever sent them — until now, keeping photos out of the job record depended on the app doing it before uploading, so an out-of-date browser or tablet could still push them back inside. The server now moves any photo it receives into file storage before saving, so a job record can no longer be bloated by an old device. If storage is briefly unavailable the photo is kept in the record rather than lost, and moved on the next save.
- AddThe same photo is only ever stored once — each file is now named after its own contents, so re-saving a job doesn't pile up copies, and a photo attached in two places on the same job takes one slot rather than two. On the live data that alone removed a duplicate 99 KB image.
v0.27.3
25 July 2026
- FixA tab left open could quietly undo work done elsewhere — each app keeps a copy of everything on the device so it opens instantly and keeps working out of range. But a tab that had been sitting on an old copy could send it back to the server before reading what was there, wiping out anything changed in the meantime — another dispatcher's edits, or a maintenance job. This was caught in the act: a housekeeping task moved 376 KB of photos out of three jobs, a dispatcher screen opened on a stale copy, and its automatic save put all of them straight back. Nothing is now sent to the server until the app has read what's there and combined it with your own changes. Your work is never lost in the meantime — it's held on the device and goes up as soon as the two are reconciled, the same way it already worked out of coverage.
- FixPhotos moved to file storage can't be dragged back into the job record — once a photo or signature lives in file storage, that's a one-way trip. Any older copy of the same job now loses to it when the two are combined, so a device that has been offline for a while can't undo the tidying.
v0.27.2
25 July 2026
- FixOne outsized job could stop everything else saving — a job that carries its photos inside its own record can grow past the size limit for a single database row. When that happened the save didn't just skip that job: nothing at all was saved, including the two dozen unrelated jobs travelling with it, and the error named no job so there was nothing to act on. The system now sets the outsized job aside, saves everything else, and tells you exactly which job is too big and by how much.
- FixA driver is no longer told “Synced” when their work hasn't saved — the sync badge treated anything it didn't recognise as success, so a refused save could show green. A refused save now shows red, names the job, says to call the office, and stays on screen instead of fading after a couple of seconds. Retrying can't fix an outsized record, so it no longer pretends to be trying.
- AddA tool to slim down jobs saved before photos moved to file storage — photos and signatures captured from v0.27.1 onwards are stored separately, but older ones are still inside their job records. One command moves them across, checking each file is readable in its new home before removing the old copy, and reports the saving. Left as a deliberate step rather than something that happens on its own, since it rewrites live records.
v0.27.1
25 July 2026
- AddSignatures, photos and permits are now stored properly instead of inside the job record — they used to be embedded in the consignment itself, and the database caps a single record at 400KB. A proof of delivery with a signature and a few photos could quietly exceed that: the save failed and the POD sat in the driver's sync queue instead of reaching the office. Media now goes to private cloud storage and the record keeps only a link, so a POD can carry as many photos as the job needs.
- AddThe upload is deliberately forgiving — with no backend, before the new route is live, or on any failure or slow link, capture falls back to holding the image on the device exactly as before. A driver confirming a delivery is never blocked by connectivity, and nothing is lost to a failed upload.
- AddMedia test suite (
node backend/tests-media.js — 23 assertions) covering upload, permitted file types, oversize rejection, a byte-exact round trip, unknown keys, path traversal and the not-yet-configured case. Wired into CI and the backend deploy gate.
- FixThe regression suite was silently skipping late-resolving asynchronous checks — it printed success before they ran. The harness now waits for all of them, which brought five previously-unrun proof-of-delivery assertions into the count (179 total).
v0.27.0
25 July 2026
- FixLists no longer hide their right-hand columns on a phone — a six-column list like Consignments, Clients or the Events log is wider than a phone screen, and the extra columns were simply cut off with no way to reach them. On Consignments that meant losing Status and ETA — the two you check when someone rings to ask where their load is. Each list now scrolls sideways on its own, with a soft shadow on whichever edge still has more to show, so you can see at a glance that there is.
- FixPinch-to-zoom works again in the Transport Manager — zoom had been switched off, which on a dense screen full of connote numbers is exactly the wrong choice. You can now zoom in on any screen.
- AddThe menu behaves like a menu on a phone — tap the ☰ and the page behind now dims; tapping the dimmed area closes the menu, which is what most people try first. The page behind also stops scrolling underneath it, so a swipe moves the menu rather than the list you can't see.
- AddYou can reach the whole menu from the keyboard — the nav items were clickable but not tabbable, so keyboard and screen-reader users couldn't get to them at all. They're now proper links: Tab to them, Enter to go, and middle-click or right-click to open a screen in a new tab.
v0.26.9
25 July 2026
- AddThe whole app can now be driven from the keyboard — dispatchers live in these screens all day, and rows in the consignment, client and event lists could only be opened with the mouse. Every clickable row now takes a tab stop and opens with Enter or Space, and the highlight showing where you are is finally visible against the brand colours.
- FixDialogs no longer trap you — Escape closes any dialog in either app (running the same tidy-up as the ✕, so nothing is left half-saved), focus moves into a dialog when it opens and returns to exactly where you were when it closes, and Tab now cycles inside the dialog instead of wandering onto the page behind it. Covers all twelve dialogs across the dispatcher and the driver app, which are also properly announced to screen readers now.
- AddCtrl-K (⌘-K on a Mac) jumps straight to the search box from anywhere.
v0.26.8
25 July 2026
- AddSend customers a tracking link that just works — until now a customer had to open the portal, sign in and pick their account before they could see anything. Each job now has its own link that opens straight to that shipment, no sign-in: live map, status, ETA and proof of delivery. Copy the link, copy a ready-written update, or open it in your email client already addressed and filled in.
- AddThe link covers one job and nothing else — it carries a long random code unique to that consignment, so holding one link reveals nothing about any other customer or job, and the account switcher and menus are hidden for anyone arriving that way. If a link goes astray, Revoke kills it and issues a fresh one.
v0.26.7
25 July 2026
- AddThe screen heading now stays put while you scroll your run — “Today's run”, the driver name and the next-job time used to slide up out of sight as soon as you scrolled down the job list. The heading now sits pinned just below the dark header, so on a long run you can always see which screen you're on and whose day it is.
- FixThe vehicle line no longer spills out of the header — when the sync status pill appeared, the driver name, the pill and the asset line together were taller than the header allowed, so the asset line dropped out below it and sat over the page as a half-cut grey line. The header now sizes itself to what it holds, and the pill takes the asset line's place while it's showing rather than adding another row — which also means the header no longer changes height every time your work is saved.
v0.26.6
25 July 2026
- FixReverted the previous release's change to how we ask for positions — v0.26.2 changed the field name to lower case on the strength of a note at the top of our own file. The provider's published documentation says otherwise: the field sent in the request and the field that comes back in the reply are deliberately spelled differently, and our note had recorded the reply's spelling as though it were the request's. Both spellings were then tried against the live service and both returned the same empty answer, so the field name was never the reason the map is empty. Restored to what the documentation specifies, and the misleading note corrected so it cannot send anyone the same way again.
- ChangeLive tracking is now confirmed to be waiting on the GPS provider, with our side ruled out — their service accepts every position request and deliberately answers “nothing” for every vehicle, including when tested on their own website using a vehicle from their own list. Every way of asking has been tried: both spellings of the field, with and without a login, and four different request types. The likeliest explanation is that our account may list the fleet but not read positions, which would also explain why their earlier fix changed nothing. Raised with them; positions will appear on the next refresh once resolved, with no change needed here.
- ChangeA deliberately empty answer is now named as such — counted and reported separately from “this vehicle has no position right now”, so the two can never be confused again.
- ChangeRemoved the temporary self-check — it answered its question. Left in, it would have made three extra requests to the provider every fifteen seconds for as long as the feed stayed empty.
v0.26.4
25 July 2026
- FixThe bottom tab bar didn't sit right on an iPhone — on iPhones the screen curves in at the bottom and the system keeps a strip there for its own home bar. The app was told to leave room for it, but the way it was written took that room out of the tab bar instead of adding it on, so the five labels were squeezed into the top half of the bar with an empty white band underneath. The bar is now the right height on a phone, the labels sit where they should, and the buttons no longer reach into the strip where the phone would swallow the tap. The Drive screen still fills exactly one screen with no scrolling.
- AddAutomatic checks for this, on every push — no test machine has a notch or a home bar, which is why this reached a real phone. The checks now run the driver app against a stand-in for an iPhone's measurements, in both the installed-app and browser cases, and fail the build if the tab bar, the labels or the Drive screen don't fit. Confirmed they catch the fault that was reported.
v0.26.3
25 July 2026
- FixThe check that guards a version bump wasn't checking the release notes themselves — it looked for the version number on this page and stopped there, so a release whose notes had been lost while combining two people's work still counted as complete, heading and all. (That is exactly what happened to the v0.21.3 notes, restored in v0.26.1.) It now confirms every release actually has its notes, that none are duplicated, that the newest release is the one highlighted, that no unresolved merge leftovers made it into the page, and that the page's own structure is sound — and it runs on every push, so a half-finished bump fails the build instead of reaching the live site.
v0.26.2
25 July 2026
- FixWe were asking the GPS provider for positions using the wrong field name — one letter of the wrong case. Their system accepted every request, reported no error, and returned an empty answer each time, which is what it does when it isn't told which vehicle to look up. The new reporting added in the last release is what made this visible: 120 requests, 120 successes, nothing in any of them. Corrected to the name their documentation specifies.
- AddA self-check for when a whole sweep finds nothing — rather than change one thing and redeploy to see, the system now tries the other plausible ways of asking and reports which one works. It only runs when nothing at all came back and there is time to spare, so it costs nothing in normal operation, and it is removed once tracking is confirmed working.
v0.26.1
25 July 2026
- FixSaved work could be silently lost when the database throttled a write — the state API writes in batches, and DynamoDB is allowed to reject part of a batch while still reporting success. Those rejected records were being discarded, and because the API replied “OK” the app cleared its sync indicator over work that never landed. Rejected records are now retried with backoff, and if any still can't be written the API says so instead of acking — so the app keeps the change pending and re-sends it (the write is a full, idempotent snapshot) until the database confirms it.
- ChangeTighter portal buttons in the sidebar — the Client Portal and Driver Portal shortcuts have dropped their second line of description, freeing vertical space at the bottom of the navigation.
- AddTests now cover the state API —
node tests/run.js also exercises the backend save/load endpoint with a stubbed DynamoDB (no AWS account or network needed): batch splitting at the 25-item limit, scan pagination, retry of throttled writes, refusing to ack a partial write, and route/error handling.
v0.26.0
25 July 2026
- AddThe map now says why it has no vehicles to show — an empty map looked the same whether the GPS provider was refusing calls, answering with no position, or the assets in that batch were trailers with no tracking unit fitted. Those are three different problems with three different fixes, and it now reports which, including a sample of the reply it got back. No positions, addresses or driver names are included.
- FixAssets no longer disappear into one another — vehicles were identified by their plate, and in the real register the plate field doubles as a status note: 222 of the 1189 assets share just 13 values between them ("3G" on 87, "SPARE" on 61, "U/S" on 41) and another 72 are blank. On the map those groups collapsed into a single marker each, and importing the register quietly brought in 908 of 1189 — the rest overwrote each other or were skipped for having no plate. Everything now keys on the provider's own asset number, which is unique.
- FixAssets with no plate can be tracked live — choosing which asset types refresh every cycle also matched on the plate, so anything with a blank one could never be selected, and ticking a type that included a "SPARE" would have pulled in all 61 of them. Existing selections keep working unchanged.
v0.25.3
25 July 2026
- FixLive vehicle tracking is working again — the map had been failing to save each new batch of positions. A field recording "this sweep was cut short" was left blank rather than set to "no" whenever a sweep in fact finished cleanly, and the database rejects a blank field outright. It could only ever appear once the GPS provider started responding properly, because until then every sweep was being cut short and the field was always filled in — so it surfaced at the exact moment everything else started working.
- FixThe system no longer blames the GPS provider for its own faults — that failure was reported as "can't reach Fleet Dynamics", which is what it says when the provider really is down. Someone would have gone to them about a problem at our end. Faults on each side are now reported separately, and the deployment check fails loudly on ours instead of passing it off as a provider outage.
- FixClosed the testing gap that let it through — the stand-in database used by the tests accepted blank fields that the real one rejects, so all sixteen checks passed on code that could not work in production. It now enforces the same rule, and two new checks cover a clean sweep saving correctly and faults being attributed to the right system.
v0.25.2
25 July 2026
- FixPublishing from GitHub works again — the cloud provider was refusing the deploy because it expects to be told which repository is asking using permanent internal ID numbers, not just the account and project name. Names can be given up and claimed by someone else; ID numbers can't, so this is the provider being careful rather than anything being wrong at our end. Corrected, and the working setup is now written down with the reasoning, so the next person doesn't lose an afternoon to an error message that means four different things.
- FixDeployment notes brought back in line with how it actually works — three places still warned that deploying the backend would wipe the Fleet Dynamics login and take live tracking down. That stopped being true in v0.24.0, when the login moved into secure storage the system reads as it runs. Also adds the exact permissions a backend deploy needs, ready to paste, instead of a list to translate by hand.
v0.25.1
25 July 2026
- FixWorking out why the new deploy button is being refused — the cloud provider rejects the deploy with a single unhelpful message that means any one of four different things. A temporary diagnostic action prints what the deploy asks for alongside what it is actually being given, so the mismatch can be read off directly instead of guessed at. No effect on the apps; it comes out again once the deploy authenticates.
v0.25.0
25 July 2026
- AddDeploy the backend from a button instead of a laptop — a new Deploy backend action runs the whole deployment on a clean Linux machine in the cloud: no software to install, no credentials on anyone's computer, and none of the Windows quirks that caused six separate failures getting the last release out. It runs the full test suite first, then checks the live GPS feed afterwards and says plainly what came back. Still started by hand, since a backend deploy changes real infrastructure.
v0.24.2
25 July 2026
- FixLive GPS came back "not authorised" after the last deploy — the same Windows path rewriting reached further than first thought: it also corrupted the storage location recorded in the deployed permissions, so the system was denied access to its own credentials. Fixed in the deploy script too, and all three scripts now refuse to run rather than deploy a corrupted path.
v0.24.1
25 July 2026
- FixStoring the Fleet Dynamics login failed on Windows — the Git Bash terminal silently rewrites anything that looks like a folder path before passing it on, which mangled the storage location and had AWS reject it. It also meant the deploy couldn't find credentials that had been stored. Both scripts now switch that rewriting off.
v0.24.0
25 July 2026
- ChangeThe Fleet Dynamics login is stored securely in AWS and no longer typed at every deploy — it's kept encrypted in AWS Parameter Store and read by the system as it runs. Store it once and deploys stop asking. Changing the password later is a single command with nothing to redeploy.
- FixA deploy can no longer switch live GPS off by accident — because the credentials used to be handed over at deploy time, a deploy run without them would quietly replace them with blanks and take the live map down until someone noticed. Deploys no longer touch the credentials at all.
v0.23.1
25 July 2026
- FixThe asset import would have failed with "not found" — the new import was built and working, but the address it lives at was never registered with the API gateway, so the request never reached it. Registered now, with an automatic check that every address the system answers on is actually published — the same mistake can't ship again.
v0.23.0
25 July 2026
- AddAsset register — import every asset and group it by type and depot — a new section on Settings pulls the full list of assets from Fleet Dynamics (all 1,189: prime movers, rigids, trailers, buses, light vehicles and plant) and lets you sort them into types and depots. Search by plate or driver, filter by type or depot, select everything matching and assign in one go — practical for a fleet this size. Re-importing later picks up new assets and refreshes drivers without touching the grouping you've already done.
- AddChoose what gets tracked live — tick a type (prime movers and rigids by default) and those assets refresh on the map every 15 seconds, while everything else rotates through in the background. The change takes effect on the next refresh — no deploy, no waiting. Types can be renamed, added and removed to match how the yard actually talks about the fleet.
v0.22.0
25 July 2026
- AddLive Fleet now works with the full asset base — Fleet Dynamics granted access to all 1,189 assets (trucks, buses, light vehicles, trailers), which is far more than can be asked for individually every 15 seconds; the map was coming up empty as a result. Positions are now gathered a slice at a time and built up, so the map fills in and stays current instead of showing nothing. Vehicles marked for live tracking are refreshed every cycle; everything else rotates through in the background, covering the whole fleet every few minutes at a fraction of the load.
v0.21.8
25 July 2026
- FixDeploy was publishing internal files to the website — the build configuration, the data-model diagram and source-control settings were being uploaded alongside the apps and were reachable on the public web address. Nothing sensitive was exposed (passwords are never stored in the project), but they don't belong on a customer-facing site and are now excluded.
v0.21.7
25 July 2026
- FixDeploy updated the backend but couldn't upload the website — the AWS command line on Windows ends its output with an invisible carriage return, which was being carried into the storage bucket name and rejected as an invalid name. Every value read back from AWS is now cleaned before use.
v0.21.6
25 July 2026
- FixDeploy hit Windows' 260-character path limit — the build copies the bundled AWS libraries into a folder named after each function, and the new background GPS refresher had a long enough name to tip the deepest file over the limit, failing with an unhelpful "cannot find the path specified". The function has been given a shorter name, and the deploy script now measures the folder it's running in and warns up front if it's too deep, with the fix, instead of letting the build collapse.
v0.21.5
25 July 2026
- FixDeploy could fail with an "Access is denied" crash when the project sits in OneDrive — the build step starts by deleting its previous output, and OneDrive keeps files open while it syncs them, so the deletion failed and the deploy stopped with a page of technical error text. The old build is now cleared beforehand, and if something really is holding the files, the message says so and suggests pausing OneDrive rather than dumping a stack trace.
v0.21.4
25 July 2026
- FixDeploy script wrongly reported the AWS SAM tool as missing when it was installed — its Windows installer provides
sam.cmd, and Git Bash only recognises .exe commands, so a working installation was invisible and the script sent you off to reinstall something you already had. It now asks Windows where the tool is, confirms it actually runs, and makes it available for the rest of the deploy.
v0.21.3
25 July 2026
- ChangeThe side menu now scrolls as one piece — logo included — the Northfleet logo used to be pinned above the menu, so on a laptop or phone the menu items were squeezed into a small scrolling strip between the logo and the portal links. The whole sidebar now scrolls together: the logo slides away as you scroll down to Reports, Help and Settings, and the menu gets the full height of the screen. On phones the logo and menu rows are also a little more compact, so more of the menu is visible when you open it.
v0.21.2
25 July 2026
- ChangeThe deploy script now lists everything that needs fixing at once — it checked prerequisites one at a time, so a machine missing two of them made you install, re-run, and discover the next one. It now checks the tooling and the AWS sign-in together and reports them as a numbered list, with the install command for each.
v0.21.1
25 July 2026
- AddDeploying is now one command —
./deploy-guided.sh replaces a sequence of commands that had to be edited before running. It checks the tools and credentials are working, finds the website's storage and CDN settings by itself, asks for the Fleet Dynamics login (password hidden, and not left behind in the terminal history), deploys, and then tests the live GPS feed and explains what came back. If it can't confirm where the website lives it stops rather than updating half of the system.
v0.21.0
25 July 2026
- ChangeLive Fleet now reads from a shared position snapshot — the map used to ask Fleet Dynamics for every vehicle's position on every refresh, from every open tab, which worked out at roughly 84 calls a minute per screen left open (a mounted depot monitor polled all day and night). The backend now keeps one shared snapshot that every screen reads instantly, and refreshes it in the background at most once every 15 seconds no matter how many people are watching — and not at all when nobody is. Same live map, a fraction of the load on Fleet Dynamics, and the map no longer waits on their server to draw.
- FixThe map keeps showing the last known positions if the GPS feed drops — rather than going blank while the feed recovers. Positions are marked stale, and if the feed stays down long enough that a position would be misleading, the fleet indicator turns red instead of showing an old fix as though it were live.
- ChangeEvery change is now checked automatically before it can be merged — a continuous-integration pipeline runs the full test suite (business logic, the live-fleet snapshot, and the Fleet Dynamics timeout handling), checks every script file parses, and validates the deployment template, on every push and pull request. A broken change shows a red cross on the pull request instead of reaching a deploy.
- AddTwo new backend test suites — covering the shared live-fleet snapshot (including many screens refreshing at once) and the GPS timeout protection added in v0.18.2, which previously had no automated coverage.
v0.20.0
25 July 2026
- AddBuild version on screen in all three apps — the dispatcher already showed it at the foot of the sidebar; the client portal now carries it in the page footer and the driver app at the bottom of the screen above the tab bar. Useful for telling at a glance which build a device is actually running, particularly a driver tablet that may be holding an old cached copy. It's hidden on the driver's Drive screen, which is deliberately sized to fit one screen with no scrolling.
- ChangeOne place to set the version — all three apps now read
NF.version from the shared data layer instead of the number being typed into each page, so a bump can't half-land and leave an app claiming the wrong build.
- FixDriver app: an invisible bubble was sitting on the Pre-start tab — the "saved" message bubble is parked just off the bottom of the screen between uses, but in the driver app it wasn't parked far enough and stayed on the tab bar: a faint dark pill over Pre-start, and worse, taps on the middle of that tab landed on the bubble instead of the tab and did nothing. The bubble is now properly hidden between uses and can never take a tap.
v0.19.1
25 July 2026
- AddDrive screen: one map button for the whole leg — at the follow zoom a stop 180 km up the road sits well off the screen, so the map now has a single button that switches between following the truck and fitting the whole leg (truck and stop both in view). It hands the view back to the truck by itself after 15 seconds, so the map can't be left zoomed out, and the same button doubles as Follow truck after you've panned the map by hand. Replaces the earlier Recentre button.
- AddBrowser checks for the Drive screen —
cd tests/manual && npm install && node drive-screen.js runs ~45 checks over the one screen the main test suite can't reach: layout at tablet and phone sizes, touch-target sizes, the map (right tiles for the GPS fix, following, the whole-leg toggle, sizing after tab changes and rotation), over-limit warnings, losing GPS, one-tap time capture and the HQ banner. It fakes the GPS and generates its own map tiles, so it needs no internet and can gate a deploy. Optional and kept out of tests/run.js, which stays dependency-free.
- FixDrive screen kept showing the last speed after losing GPS — the speedo held its final reading instead of blanking, which also held the arrival/departure lock shut: if the signal dropped at a remote site while the last reading was highway speed, the driver couldn't record their times. Losing the fix now clears the speed, releases the lock, and the distance readout says it's working from the last known position.
v0.19.0
25 July 2026
- ChangeDriver portal — Drive screen rebuilt for a tablet mounted landscape in the cab — three columns that fit the screen with no scrolling: speed, posted limit and the countdown to the next break on the left; a live map on the right of it; and the next stop with its buttons on the right-hand side, closest to the driver on a centre-mounted tablet. Every button is at least 64 px tall, the speed reads at a glance, and the chrome slims down in landscape to give the display the height. On a phone it stacks back into one column with the map last.
- AddLive map on the Drive screen — replaces the static Google embed with the same map used on Live Fleet, showing the truck's own GPS position, a marker on the next stop and the line between them. It follows the truck automatically; panning it puts a Recentre button up until you tap it. The map library is cached with the app so it still loads without signal (tiles need a connection).
- AddDistance and ETA to the next stop — straight-line distance and an arrival time from current speed, labelled as such (it's not a road-network ETA).
- AddArrival and departure times from the Drive screen — one tap records the next time in the job flow with GPS attached, without opening the docket. It shows the next step only, and locks above 15 km/h — times get recorded at the stop, not while rolling. Signatures still go through the docket: when a pickup release or delivery POD is what's due next, the button takes you straight to the signature pad.
- AddNext stop follows the run — the Drive screen points at the pickup until you've left it, then switches to the delivery, and offers the site's phone number alongside the call to operations.
- AddMessages from HQ show up on the Drive screen — an unread message from dispatch appears as a full-width banner in the actions column instead of only a small badge in the top bar. Work-today and since-break totals from the work diary now sit under the break countdown.
- FixDriver portal showed a permanent unread-mail dot — the badge on the messages button stayed visible with no messages behind it.
v0.18.2
25 July 2026
- FixLive Fleet GPS proxy: two more layers of timeout protection — live testing showed the Fleet Dynamics server can stall a connection in a way the standard request-cancel never fires on, riding straight into the backend's hard 15-second kill (opaque error, no JSON). Every FD request now has a backstop timer that cuts it off even if the cancel signal is ignored, and the API handler itself answers with a clean
fleet_dynamics_unavailable response just before the deadline no matter what hangs beneath it. The Live Fleet map now always gets a proper answer — positions, a partial sweep, or a clean "GPS offline".
v0.18.1
25 July 2026
- AddAutomated regression tests —
node tests/run.js runs ~110 assertions over the business logic (pricing zones and lane rates, demurrage including midnight crossings, document expiry, job-form applicability, client agreement rules, invoicing totals, messaging unread counts, incidents, and the integration inbox). Dependency-free and exits non-zero on failure, so it can gate a deploy.
- FixInbound request IDs could collide — found by the new tests: a batch of job requests arriving in the same millisecond was given identical IDs, so accepting one could act on the wrong record. IDs are now collision-resistant, with a test pinning the behaviour.
v0.18.0
25 July 2026
- AddReports upgraded to the money and compliance picture — revenue by customer and by lane (from approved/draft invoices), demurrage charged and how much has been notified, and a compliance snapshot showing open incidents, unfinished job forms, oversize loads with no permit attached, asset documents expiring or expired, and connotes missing a required client reference.
- AddCSV export for accounts & payroll — download consignments, driver timesheets, invoices, demurrage or incidents straight from Reports (opens in Excel).
- AddHelp rewritten for everything added since launch — a step-by-step how-to for depot monitors (which screens to mount, how to open one, F11 full screen, how it self-refreshes), how-tos for messaging a driver, charging demurrage, attaching a permit, point-to-point pricing, the Job Inbox, approving invoices and exporting for accounts, plus glossary entries for demurrage, pricing zones, RAV road access, load checks, job forms, the EWD, incidents and inbound requests.
v0.17.0
25 July 2026
- AddJob Inbox — customer system integration — customer systems (e.g. Coates' hire system, Water Corp) can lodge transport requests straight into FleetView. They land in a new Job Inbox for dispatch to review rather than auto-creating work: accept and it's booked as a connote carrying the customer's own reference (Load ID / job number) so their paperwork matches ours, or reject it with a reason. Unactioned requests show a badge. The inbound adapter (
NF.Integrations) is swappable for a real API, EDI or mailbox feed.
v0.16.0
25 July 2026
- AddDepot monitors for any screen — wall display mode now works on any route, not just the dashboard:
#/schedule?wall puts the weekly run plan (with its conflict warnings) on a mounted depot screen, and #/jobs?wall / #/events?wall do the same for the dispatch board and incident feed. Wall mode gets a branded header with a live clock, enlarged type for reading at distance, interactive clutter removed, and a 60-second self-refresh so the monitor never goes stale. Launch links are on the Settings screen.
v0.15.0
25 July 2026
- AddJob forms for specialised work ("behind the job" paperwork) — crane/Franna jobs now carry a Jacking & crane setup form (ground conditions, outrigger pads/packing, ground bearing pressure, levelling, exclusion zone, overhead clearance, spotter) and float/over-dimensional jobs an Oversize route form (permit route, signage, pilot/escort, travel curfew). The right form appears on the driver's docket automatically based on the assigned asset — required fields are enforced — and dispatch sees every answer on the consignment, with outstanding forms flagged.
v0.14.0
25 July 2026
- AddZone pricing & point-to-point lane rates — pricing is now set per zone pair (8 zones covering the metro, South West, Mid West, Goldfields, Pilbara coastal/inland and Kimberley), so a slightly different address inside the same zone no longer means re-touching the rate. Quoting recommends the flat point-to-point price per vehicle class for the lane, and surfaces that lane's road access rating and permit requirement. The full lane matrix is visible in Settings.
v0.13.0
25 July 2026
- AddAttach permits & job documents — dispatch can attach a permit, escort order, site induction or SWMS (photo or PDF) to a consignment, with a reference number. Attachments sync to the driver's tablet and open from the docket, so the driver can produce the permit on the road. When a load has been measured oversize and no permit is attached, the panel says so in red.
v0.12.1
24 July 2026
- FixRobustness sweep — the Consignments list (and search) no longer break if a record has an unresolved customer or depot; all such lookups now fall back to "—". Stray empty test records are pruned on load so they can't re-appear via sync or clutter views. Every screen was smoke-tested to render cleanly.
v0.12.0
24 July 2026
- AddAutomated invoicing + reviewer workflow — finishing a job (sent for invoicing) now auto-drafts an invoice with line items from the linked quote (or a rate-card estimate) plus any demurrage and GST. A new Invoicing screen gives the reviewer a queue: see the lines and total, then Approve for billing or flag a Query. A badge shows drafts awaiting review. Persisted + synced.
v0.11.0
24 July 2026
- AddAlternate asset suggestions — the schedule conflict panel now names the free prime movers, trailers or drivers for that day next to each clash (double-booking, maintenance, unavailable/fatigue), so dispatch can reallocate in one glance. When nothing's spare it says so, prompting a swap or hire.
v0.10.1
24 July 2026
- FixLive Fleet GPS proxy hardened against a stalling Fleet Dynamics server —
/fleet/live now works to a strict ~12-second wall-clock budget and returns whatever vehicle positions it has gathered so far (flagged partial) if the FD server stalls mid-fleet, instead of hanging past the Lambda's 15-second limit. The map degrades gracefully and the next poll fills in the rest.
v0.10.0
24 July 2026
- AddElectronic Work Diary — the driver's Diary tab now tracks work vs rest across the day with running totals and HVNL compliance bars (work today vs 12 h, continuous work vs the 5¼-hour break rule), with alerts as limits approach.
- AddDriver timesheets — Reports shows per-driver hours for the day, derived from each job's start→finish captures (first start, last finish, total worked), flagging anyone over 12 hours.
v0.9.0
24 July 2026
- AddLoad & dimension check — a pickup-time verification on the driver's job: a restraint checklist plus measured length/width/height/mass, with live flagging when the load is oversize / over-mass (over general limits → permit required) and an optional photo. Result shows on the consignment for dispatch, and an oversize load raises an alert.
v0.8.0
24 July 2026
- AddAsset documents & compliance — drivers can reach their vehicle's registration, insurance, permits and inspections plus fleet-wide SWMS & policies from the Truck screen, each with an expiry status (valid / due soon / expired). Dispatch gets a Fleet documents & compliance table in Settings that flags anything expired or due within 30 days.
v0.7.0
24 July 2026
- AddDriver incident reporting — drivers can report a breakdown, hazard, near-miss, accident or load issue from the Truck screen or the Drive screen: type, severity, notes, photos and GPS. It's sent straight to dispatch (raises an event, high severity flagged critical) and lands in an Open incidents panel on the Events Log where dispatch can mark it resolved. Persisted + synced.
v0.6.0
24 July 2026
- AddDemurrage tracking + automatic customer notification — waiting time at pickup/delivery (from the captured arrive→depart times) beyond the free allowance is detected automatically, charged per hour at the zone rate, and flagged on the consignment. Recording a departure raises a demurrage event and marks the customer notified; a Notify customer button re-sends. Customers see a clear demurrage notice on their tracked shipment in the portal. Free time / fallback rate are in Settings.
v0.5.0
24 July 2026
- AddHQ ↔ driver messaging — two-way messages between dispatch and the driver's tablet. New Messages screen in the dispatcher (pick a driver, chat, unread badges) and a message button on the driver app with its own unread badge. Persisted and synced like all shared state, so a message sent on one device appears on the other.
v0.4.0
24 July 2026
- AddAutomated schedule conflict detection — the Schedule now flags, at a glance, when a prime mover, trailer or driver is double-booked on the same day, when a driver is rostered on a fatigue/rest or unavailable day, or when a truck is booked while in maintenance. Critical clashes show red; tap a conflict to highlight the affected cell on the grid. Read-only — it never changes the roster for you.
v0.3.1
24 July 2026
- AddDrive screen now reads the posted speed limit automatically from the driver's GPS location — no need to set the zone by hand. Uses OpenStreetMap
maxspeed data via the free Overpass API (new swappable NF.SpeedLimit adapter). Falls back to manual limits where the map has no data; an Auto toggle switches between map-detected and manual.
v0.3.0
24 July 2026
- AddDrive screen in the driver app — an always-on display for use while driving. Live speedometer with an over-speed warning (from the device GPS), a time-until-next-break bar (HVNL 5¼-hour guide, with tappable zone limits), an embedded map with one-tap turn-by-turn navigation to the next stop, and a call operations button. Holds a screen wake-lock so the display stays on.
v0.2.2
24 July 2026
- AddThe Driver portal is now an installable PWA — drivers can add it to their home screen and open it full-screen, with its own icon and splash. Scoped to
/driver/ only; the dispatcher app and client portal are unaffected.
- AddWorks offline: a service worker precaches the run-sheet shell (HTML/CSS/JS, shared data layer, icons, fonts), so the app opens and renders with no signal. Deliveries, times and PODs keep saving to the device.
- AddResilient sync queue — changes made offline are held on the device and pushed to the backend automatically once the connection returns (retried on reconnect and on a background timer). A status pill in the top bar shows Offline · saved on device, Syncing… or Synced.
- AddIn-app Install banner — drives the native add-to-home-screen prompt on Android/Chrome, and shows Share-sheet instructions on iOS. Dismissible, and auto-hidden once the app is installed.
- AddOne-command AWS hosting —
infra/site.yaml provisions a private S3 bucket + CloudFront (HTTPS, directory-index rewrite for /driver/ & /portal/, correct PWA headers). New-account runbook in infra/DEPLOY-NEW-ACCOUNT.md.
- ChangeBackend Lambda runtime bumped to
nodejs24.x (Node 20 is past end-of-life); deploy.sh no longer needs Node to write config.js.
- FixLive Fleet Dynamics GPS feed — the backend proxy now calls the ASMX
loginxml/selectshowxml operations correctly (operation as a URL path segment; vehicleId casing), instead of POSTing to the base URL (which the server tried to parse as SOAP and rejected). A valid login with no vehicles now returns an empty fleet (200) rather than an error.
- Change
NF.Store now tracks unsynced state and replays the full snapshot until the API accepts it (idempotent, last-writer-wins). No behaviour change when no backend is configured.
v0.2.1
23 July 2026
- AddPer-customer connote & invoicing rules, all configurable on the Clients screen: a required custom reference (e.g. Coates Load ID, Water Corporation Job number) and an invoices-per-PO policy.
- AddRequired references are enforced — a consignment can't produce its connote or be sent for invoicing until the reference is entered.
- AddOne-invoice-per-PO customers (Coates) are blocked from billing a second job against an already-invoiced PO; annual-PO customers (Water Corporation) can raise multiple invoices against the one PO.
- AddWater Corporation added as a client with its annual PO and Job number rule preconfigured.
v0.2.0
23 July 2026
- AddLive Fleet Dynamics GPS integration — the dashboard and Live Fleet maps now show the real fleet, polled every 15s from the actual telematics feed.
- ChangeFleet data comes from Fleet Dynamics (login + per-vehicle telemetry) proxied server-side through the AWS backend, so credentials never reach the browser.
- ChangeNo simulated trucks in production: if the GPS feed is unreachable the map holds the last known positions, flags them stale, and the Fleet Dynamics indicator turns red.
v0.1.9
23 July 2026
- FixDashboard map rendered blank —
#dash-map was inheriting height:100% from the full-page map rule and collapsed to zero once its card stopped stretching. Mini-map now has a fixed 340px height.
v0.1.8
23 July 2026
- AddClient portal now shows delivery photos alongside the signature on proof of delivery — tap a thumbnail to view full size.
- ChangeDriver run cards now show the connote number prominently under the customer name.
- AddVersion number links to this changelog.
- ChangeDashboard map and Fleet status cards uncoupled — the fleet list scrolls within its own card instead of stretching the map (fixes the blank/oversized map).
v0.1.7
23 July 2026
- FixDashboard & Live Fleet maps could load centred over Indonesia — maps now re-centre on Western Australia after layout settles (double-pass, no animation).
- FixEliminated the Leaflet
_leaflet_pos console crashes caused by state-sync re-rendering a torn-down map.
- FixDriver docket now updates on screen the instant a time is stamped — state sync no longer orphans the open consignment.
- FixStopped idle browser tabs from overwriting fresh changes: state only saves when something actually changed.
- FixArrival toasts & alerts now show clean asset numbers (e.g.
NF213, not NF-213).
v0.1.6
July 2026
- ChangeMain-app consignment page rebuilt to use the same guided job-flow as the driver portal — the two are now kept in sync.
- FixTime-stamp buttons update the screen immediately, then attach GPS in the background.
- FixFixed scrolling where docket sections rolled under sticky headers/footers.
- AddAd-hoc connote creation in the driver portal.
- AddMulti-photo proof of delivery (driver portal and main app).
v0.1.5
July 2026
- AddServerless backend live — API Gateway + Lambda + DynamoDB; all three apps share state through the database.
- AddLogin sessions persist across refresh in the main app, client portal and driver portal.
- AddDriver time capture as a guided step-by-step flow with POD photo and QR portal links.
- AddData-model diagram (draw.io) linked from the Help screen.
v0.1.0
July 2026
- AddInitial prototype: Operations Dashboard, Live Fleet tracking, Dispatch board, Consignments with signature-pad proof of delivery.
- AddCustomer-facing Client Portal — track a shipment and book a job.
- AddQuotes lifecycle: enquiry → quote → PO → book → connote.
- AddWeekly Schedule board with driver rows, truck/trailer swaps and depot filtering.