Documentation

How AfriFleet works

AfriFleet runs a haulage business end to end: the loads, the trucks, the people, and the money. This page explains what it does and how the pieces fit, in plain language. It is written for the people who will actually run it, not only for developers.

Overview

A haulage company loses money in the gaps between departments. A load is agreed on the phone, a driver waits at the gate for dispatch cash, a breakdown is reported by calling three people in turn, and nobody knows what a truck actually earned last month until someone reconciles paper.

AfriFleet removes those gaps by putting one record at the centre: the trip. Operations, maintenance, finance and the driver all act on that same record. Nothing is re-keyed, and every action is timestamped, so the history of a load is never in dispute.

The part that is genuinely different is the money. When a delivery is confirmed, the driver's dispatch is released as a real payment on a public network, in seconds, at any hour. There is no cash desk and no waiting for a bank window to open.

The five roles

Everyone signs in to the same app and sees only their own work. The role decides what is on the screen and what the server will allow.

RoleWhat they do
AdminOwns the company account. Sets route rates, payout limits and the exchange rate. Invites everyone else and can see everything.
Fleet / OperationsAdds trucks and drivers, creates trips, assigns who runs what, and watches the board.
MaintenanceReceives breakdown reports with photos and location, diagnoses, prices the repair and approves it.
Dispatch / FinanceApproves and releases payouts, funds the treasury, issues customer invoices and records payments.
DriverSees only their own trips. Accepts a load, moves it through its stages, reports breakdowns, requests fuel and receives payment.

Access is enforced on the server and in the database, not by hiding buttons. A driver who types another page's address into the browser is refused, and a query for another driver's trips returns nothing.

An admin can preview the app as another role using the View as switcher. It changes only what is shown, never what is permitted, so it cannot be used to gain access to anything.

The trip lifecycle

A trip moves through stages, and each one is stamped with who did it and when. The stages are deliberately separate from the payment status, because a load being delivered and a driver being paid are two different questions.

  1. 1

    Draft

    The load exists but nobody is assigned yet.

  2. 2

    Assigned

    A truck and driver are attached. Neither can already be on another active trip.

  3. 3

    Accepted

    The driver confirms they are running it. Until they do, nothing moves.

  4. 4

    Loading

    Cargo is going on.

  5. 5

    In transit

    On the road. The truck is marked busy and the driver holds it.

  6. 6

    Delivered

    Proof of delivery is in. The truck and driver are released for the next job.

  7. 7

    Completed

    The payout has settled and the trip is closed.

A trip can be cancelled before delivery, which frees the truck and driver immediately. Every trip carries a full timeline, so you can see exactly when a load was accepted, when it departed, and how long it sat.

How money moves

Driver payments are released from a company treasury — a wallet the business funds in advance. Money leaves it only through an approved payout.

  1. 1

    A rate is fixed

    The admin sets what a route pays, for example Lagos to Kano. Any trip on that route fills in that amount automatically, so nothing is negotiated at the gate.

  2. 2

    The trip is delivered

    The driver marks delivery with proof.

  3. 3

    Finance approves

    Or, if the rate card allows it, approval happens automatically on delivery.

  4. 4

    The payout is recorded first

    A ledger entry is written before any money moves, marked pending.

  5. 5

    The transfer is sent

    Funds go to the driver's payout wallet.

  6. 6

    The entry is settled

    The ledger row is updated to confirmed or failed, with the transaction reference attached.

Recording before sending is deliberate. If a transfer fails halfway, there is still a record showing what was attempted, so money can never move without a trace. The transaction reference on each row can be opened in a public explorer, which means a driver disputing a payment can be shown proof rather than an assurance.

The same mechanism pays approved repairs and fuel advances, so all outgoing money runs through one auditable ledger.

Naira and USDC

The business thinks in naira. Rates, invoices and reports are all in naira, because that is what an operator quotes and what a driver expects.

USDC is the rail underneath, not the language on top. When a payout is sent, the naira amount is converted using the exchange rate at that moment, and both the naira figure and the rate used are stamped permanently on the ledger entry.

Stamping the rate matters. Six months later, a payout made at one rate still reports at the rate it was actually sent at, so historical figures do not silently change when the naira moves.

The admin sets the rate. If it has not been updated in over 24 hours, payouts are refused rather than sent at a stale figure.

Breakdowns

A driver reports a fault from the roadside with photos and location attached, so maintenance is looking at evidence rather than a description over a bad line.

  1. 1

    Reported

    The driver files the fault with photos, location and a severity.

  2. 2

    Reviewing

    Maintenance picks it up.

  3. 3

    Approved

    A diagnosis and a cost are set. The truck is marked under repair so nobody assigns it.

  4. 4

    Funds released

    The repair cost is sent to the driver so the mechanic can be paid on the spot.

  5. 5

    Closed

    The repair is done and the truck returns to service.

A report can be rejected, but only with a reason, which the driver sees. The truck is taken out of the assignable pool automatically the moment a repair is approved.

Fuel

Fuel follows the same shape: the driver requests, operations approves the litres and amount, and the money is released. What makes it useful is the odometer reading captured with each receipt.

With two readings, AfriFleet can show real consumption per truck — litres per 100km and cost per kilometre — instead of a fuel spend total that hides which vehicle is drinking. Until a truck has two readings, the figure is left blank rather than estimated, because a wrong efficiency number is worse than none.

Billing and revenue

Route rates set what a lane costs you. Customer rates set what a lane earns you. With both, margin is a fact rather than a guess.

Delivered trips can be pulled onto an invoice, which totals itself from its lines. A trip cannot appear on two live invoices at once. Payments are recorded against the invoice, and its status follows the money: sent, part paid, then paid.

Reports then show revenue, cost and profit per truck, per route and per customer, and everything can be exported to CSV for a spreadsheet or an accountant.

Email that becomes work

Customers do not want to learn new software. They send an email. AfriFleet watches an operations inbox, reads what arrives, and turns an order into a draft trip or a fault report into a maintenance ticket, then replies to acknowledge it.

Email can create work, never move money. A message can open a draft trip, but nothing in an email can approve a payment or release funds. Approval is always a deliberate action by a finance user inside the app.

Team invitations go out the same way: an admin invites someone by email and they join with the role they were given.

Companies and access

Every company on AfriFleet is sealed off from every other one. Trucks, trips, drivers, invoices and payouts all belong to a company, and the database refuses to return a row from another one.

This is enforced at the database level rather than in application code, which means it holds even if a page or a query is written carelessly. Signing up creates your company and makes you its admin; everyone else joins by invitation.

Safeguards

These exist because they are the things that lose real money.

SafeguardWhat it prevents
A trip can only be paid onceA double click or a repeated request cannot pay a driver twice.
Daily payout capA mistake or a compromised account cannot drain the treasury in one day.
Large payout confirmationUnusually large amounts need a second, deliberate click.
Stale exchange rate refusalA payout is never sized using an out-of-date rate.
Record before sendMoney can never move without a ledger row describing it.
Email cannot approveNothing arriving from outside can authorise a payment.
Company isolationOne operator can never see another operator's data.

The stack

LayerChoice
ApplicationNext.js and TypeScript, deployed on Vercel
Database and authSupabase, with row-level security enforcing access
Wallets and transfersCircle programmable wallets
Settlement networkArc, using USDC
EmailAgentMail, for inbound triage and outbound notifications

What isn't done yet

Two things are outstanding, and both depend on parties outside this project. They are listed here so nobody is surprised by them.

ItemStatus
Arc mainnetArc's public mainnet has not launched. AfriFleet runs on Arc's public testnet, which behaves identically but does not move real value. The switch to mainnet is a configuration change, not a rebuild.
Naira bank withdrawalDrivers receive USDC in a wallet. Converting that to naira in a bank account requires a payment provider integration, which is not built yet.

Want to see it running?

There's a six-step walkthrough of one load from order to payout. Or create your company and pay a driver yourself.