P2P Trading 6.2.4

2 August 2026

This release has upgrade notes. Read them before updating — they describe behaviour changes that need your attention.

ADMINDASHBOARDDISPUTESESCROWQUEUESSERVICE LEVELSCURRENCYREPORTINGACCURACYLOADING STATESLAYOUTACCESSIBILITYBUG-FIXES

P2P Trading v6.2.4

Release Date: August 2, 2026 Tags: ADMIN, DASHBOARD, DISPUTES, ESCROW, QUEUES, SERVICE LEVELS, CURRENCY, REPORTING, ACCURACY, LOADING STATES, LAYOUT, ACCESSIBILITY, BUG-FIXES

Overview

Version 6.2.4 rebuilds the P2P admin dashboard around the question it exists to answer — who is waiting on the desk right now — and corrects four things it had been reporting wrongly. It then finishes the same job on the eight screens behind it, where a page waiting for its data replaced itself with a spinner and, on two of them, said something false about the record it had not read yet.

Four figures on the dashboard change and three of them were wrong — read Upgrade Notes before comparing anything against what you recorded last week.

Requires Core v6.6.1.

Update Instructions

pnpm updator

Routine. There is no migration, no new setting and no permission to grant: every figure described below is computed from records you already hold, so the dashboard is correct the moment the backend restarts.

The work is on paper, not on the server. Three numbers you have been reading off this page were wrong, and one panel was showing you the wrong rows entirely. Before you compare this week against last week, read Upgrade Notes — and open the dispute queue once after updating, because the oldest unresolved case on your desk is one the old panel could not show you.


Highlights

The dashboard was reporting the wrong queue

The panel headed Open Disputes was not showing open disputes. It listed the five most recently filed disputes of any status whatsoever, newest first. On a desk that resolves its cases promptly that panel showed five resolved rows under a heading claiming they were open; on a backlogged one it showed the five newest complaints while the dispute that had been waiting three days sat off the bottom of the list. Its "No open disputes — great work keeping the platform healthy" empty state could only ever appear on an installation that had never had a single dispute in its life.

Money was rendered as a dollar sign glued to a raw number in six places. Since v6.2.2 the endpoint behind the page has returned every money figure per currency, with the flat single-number version deliberately left empty whenever more than one currency is in play — there is no exchange-rate source on this platform, and 1 BTC plus 1 USDT is not a number. The page read that empty value as zero. On a multi-currency desk, total volume, this week's volume, the average trade value and every trader's volume on the leaderboard all read $0, and on a desk trading in one currency that is not the dollar, all six lines printed a dollar sign in front of a euro, naira or USDT amount.

A leaderboard captioned "By trading volume" has always been ranked by completed-trade count. And a Platform Health dial reported a composite score out of 100 that nobody can act on.

The queue is now the headline. The dispute backlog sits above the fold, split into within-target, due and past-target and aged against the platform's shared 24-hour dispute target — the same budget the operations inbox counts P2P disputes against — so the two can no longer disagree about whether the same dispute is late. Below it are the numbers a P2P operator is actually exposed to, which are not trading numbers: the platform here is the escrow agent and the referee, and what it is holding is other people's money frozen in trades it has not settled.

The screens behind it

Eight P2P admin screens waited for their data by throwing away the page. The offer detail page replaced roughly 860px of known layout with a 48px spinning ring; the payment method editor discarded three form cards and rebuilt them in one frame; the offer editor reached into its own route loading file at runtime and rendered it as a second page. Four route-level pending files had drifted so far from the pages they stood in for that they were full-bleed — no page container at all — so every card ran to the viewport edge and then snapped inwards when the real page mounted.

Two of them were making claims rather than reserving space. A dispute case file said "No evidence submitted" about a party to a live dispute while the request that would have listed the evidence was still in flight, and "No admin notes yet" about a case file nobody had read yet. Both are findings. On this screen they are quite possibly the finding the case turns on.


Upgrade Notes

Four money figures on the dashboard were reporting zero, and all six carried a dollar sign that was not theirs

Since v6.2.2 the dashboard endpoint reports money per currency and leaves the single combined figure empty when several currencies are involved, because there is no exchange-rate source to combine them with. The page rendered that empty figure as 0 and glued a $ to the front of it. Total Volume, the this week figure beside it, Avg Trade Value and the volume against each name on the top-trader leaderboard all read $0 on any desk trading in more than one currency — not "unavailable", a confident zero. Separately, the amount on every recent-trade row and every dispute row was printed with a dollar sign regardless of what currency the trade was actually denominated in, so a 500,000 NGN trade read as $500,000.

  • Changed: every amount on the page is now rendered from the per-currency breakdown, showing the largest denomination with its own ticker and stating how many other currencies sit behind it. No figure on this page is a sum across currencies. A line at the top of the page says so whenever more than one is in play.

The "Open Disputes" panel was not listing open disputes

The panel listed the five most recently filed disputes of any status, newest first, under a heading that said they were open. A resolved dispute filed this morning outranked an unresolved one filed on Tuesday, and on a desk that had just cleared its backlog the panel showed five closed cases.

  • Changed: it lists the six oldest disputes that nobody has ruled on, longest wait first, with each one's age against the 24-hour target beside it. That is the same population and the same ordering as the dispute queue it links to, so the panel is now the top of that queue rather than a second, disagreeing list.

The top-trader leaderboard was never ranked by volume

The panel was captioned "By trading volume" and ranked by completed-trade count.

  • Changed: the caption now says what the ranking is. The rank itself is unchanged and deliberately so — ranking by a summed total would order sellers by whichever currency happens to have the largest nominal units, which on a mixed desk puts the smallest trader first.

The Platform Health score has been removed

  • Changed: the dial showing a composite score out of 100, and its Excellent / Good / Fair / Needs Attention label, are gone from the page.
  • Why: the score was four heuristics with hardcoded steps — the open-dispute rate, the high-priority dispute count, the pending-offer rate and the flagged-offer count — subtracted from 100. Nobody acts on "84 out of 100"; they act on the four numbers underneath it. All four are on the page, each beside a link into the rows that produced it.

The dashboard refreshes itself, and a failed refresh no longer blanks it

  • Changed: the page reloads its figures every 60 seconds, and only while the tab is actually on screen. A last updated time now comes from the server clock rather than from the browser's, and a live indicator says whether what you are reading is current, refreshing or stale.
  • What changes for a failure: a refresh that fails leaves the figures already on screen exactly where they were and marks them stale, instead of replacing a correct dashboard with an error. Only a failure with nothing behind it takes over the page — and when it does, the links to the dispute and trade queues stay reachable.

Added

The dispute backlog, aged, above everything else

  • Added a queue band across the top of the dashboard splitting every open dispute into within target, due and past target against the platform's shared 24-hour dispute budget — the tightest budget the platform keeps, deliberately tighter than a withdrawal, because escrow is held while a dispute runs and both sides are frozen out of their own money until somebody rules.
  • Added the age of the longest-waiting open dispute, computed with the same function and against the same budget the queue's own rows use, so this line and the badge on the row it refers to are one calculation.
  • Added an alert when any dispute is past the target, naming how many and how much escrow they are sitting on, with a button into the queue.

What the desk is actually holding

  • Added Escrow held — the money frozen in live trades right now, per currency, and the number of trades holding it. This is the platform's real exposure as an escrow agent and it was reported nowhere.
  • Added Frozen by open disputes — how much of that escrow is sitting behind a case nobody has ruled on.

The trade pipeline, split into the two jobs it was running together

  • Added a breakdown of Active Trades into awaiting payment (waiting on the buyer), awaiting release (waiting on the seller — the one that turns into a dispute if it sits) and in dispute.

The offer review queue

  • Added Offers awaiting review as a headline tile, aged against the platform's shared 72-hour approval budget, with the age of the oldest offer still waiting. Nobody is out of pocket while an offer waits, which is why its budget is three times a dispute's — but it is still a queue somebody has to work.
  • Added the flagged count, the live count and the all-time total alongside it as context. A raw count of every offer ever written is not a queue depth and nobody acts on it, but it is the denominator for the two numbers that are.

A throughput chart you can switch

  • Added a metric selector on the seven-day chart: trades, volume or revenue.

The offer book at a glance

  • Added a buy/sell split of the active offer book, with each side carrying its word, its arrow and its count as well as its colour.
  • Added the five most-used currencies by active offer count, as a ranked list with share bars. It replaces a donut: these are up to ten currency codes, and on a ten-slice ring everything below about 5% is a hairline and the legend ends up carrying the whole chart anyway.

Changed

Status and priority labels are translated

  • Changed the trade status and dispute priority chips on the dashboard to render translated labels. They previously printed the raw stored value — PAYMENT_SENT, HIGH — which is English shouting in all 90 languages.

The dashboard is a console, not a landing page

  • Changed the marketing hero — two gradient orbs, six floating particles and a pair of promotional buttons — for an instrument band carrying the freshness of the figures, the page title and the dispute queue, in that order.
  • Removed the Quick Actions panel of three links, two of which were already in the navigation bar directly above it.
  • Changed the entrance animation to one. Every panel on the old page re-entered from 20px below on each refresh, because the same animation pair was applied at five nesting depths.

A page that is waiting no longer replaces itself

  • Changed eight P2P admin screens so that the layout renders once and only the unknown values wait: the dashboard, the dispute case page, the offer detail page, the offer editor, the trade detail page, the payment method editor, the activity log and the settings page. Headings, labels, borders, tab strips, grid definitions and every fixed-height form control are known before the request goes out, so they render immediately and never move.
  • Changed the two editors to disable their controls while their values are in flight rather than hide the page. That is what the spinner was really protecting — the window in which typing would be silently overwritten — and hiding the whole form was a heavy way to buy it.
  • Changed five route-level pending files that had drifted into a different page altogether. Four of them had no page container at all, so they rendered full bleed and every card slid inwards to the container's width and gutter the instant the real page mounted — a sideways jump larger than any vertical one on those routes. All five also hardcoded their clearance under the navigation bar as a fixed number, which cannot follow the stacked navigation variant.
  • Removed four more that no longer stand for anything: two on list screens that rendered nothing at all, and two whose invented layouts the list pages now supply themselves.
  • Changed the dispute case page's pending state to mount the page's own components with the waiting flag pinned on, so the two states cannot disagree about anything except the data.

The P2P settings page and its pending state share one definition

  • Changed the settings page title, description and back link to be declared once and read by both the page and its pending state. They were typed out in both files with nothing keeping them in step, so renaming the page left the pending state announcing the old name until first paint.
  • Removed a second copy of the settings tab icons and descriptions that duplicated, entry for entry, what the tab definitions already carried.

Fixed

The dashboard showed resolved disputes under a heading that said they were open

  • Fixed the dispute panel querying every dispute in the system, newest first, and labelling the result Open Disputes. It now lists only disputes nobody has ruled on, oldest first, matching the queue page it links to. See Upgrade Notes.
  • Fixed the panel's ordering restarting a dispute's clock. Disputes raised automatically when a trade times out are stamped with the moment the trade was disputed, which is earlier than the moment the background job wrote the row — ranking them by the row's creation time made an old dispute look new.

Four money figures on the dashboard read $0, and two more wore the wrong currency symbol

  • Fixed the page rendering a deliberately empty multi-currency total as a zero with a dollar sign in front of it, in six places. See Upgrade Notes.

The leaderboard's caption did not describe its ranking

  • Fixed the top-trader panel captioned "By trading volume" while ranking by completed-trade count.

A dispute id that does not exist showed a loading placeholder forever

  • Fixed the dispute case page returning its loading skeleton both for "still fetching" and for "no such dispute" — so an operator following a stale link, or typing an id wrong, sat watching a pulsing placeholder for a record that was never going to arrive, with nothing on screen to say so. A dispute that cannot be found now says so and offers the way back.

The offer detail page rendered underneath the site header

  • Fixed the admin offer detail page having no header clearance, so its header card rendered behind the fixed navigation bar. It survived because the route's pending state had a hardcoded top padding that pushed the placeholder clear of the bar — so the jump into the real page looked like a skeleton drifting rather than the page being wrong.

A dispute case file asserted findings about evidence it had not read

  • Fixed the evidence tab printing "No evidence submitted" against both parties while the dispute was still being fetched. On this screen that is a finding, quite possibly the one the case turns on.
  • Fixed the case notes panel printing "No admin notes yet" about a case file that had not arrived, and the overview tab printing "No additional details provided" and a fallback dispute reason of "Dispute" before the real reason was known.
  • Fixed both parties to a dispute being named "Unknown User" while the request that would name them was still in flight — a statement that the platform could not identify them, made before it had looked.

The offer editor could write empty defaults over a live offer

  • Fixed Save being available on the offer editor before the offer had loaded. The form is driven by its own state, which is seeded from the response, so submitting in that window wrote the blank defaults over a live offer.
  • Fixed the same page reaching into its route's pending file at runtime and rendering it as a component, which made the waiting state a third copy of the page that nothing could keep in step with the other two.
  • Fixed the currency picker warning "No currencies available for this wallet type" while the currency list was still being fetched.

The payment method editor reported a method had no details configured before reading it

  • Fixed the payment-details panel showing its "No payment details configured" empty state while the method's fields were still in flight, then swapping it for the real rows.

A licence check replaced the entire P2P admin, chrome included

  • Fixed the licence gate wrapping the navigation bar and footer as well as the page. While the check was in flight the whole route tree — header, content and footer — was replaced by a single centred spinner, and the page then arrived 889px further down. The gate now wraps only the content it is gating.
  • Fixed the P2P admin shell not being a full-height column, which left the footer's position dependent on how tall the data made the page. Measured on a comparable route at 185.5px of footer travel on a page that settles inside one viewport.