/admin/runway is a forward-looking financial-health surface for investors, co-founders, and the founder. It's read-only by design — nothing on this page mutates state — and it pulls from three live data sources so what you see is always current as of page load.
Who can see it
Anyone who holds the runway.read permission. By default that's three roles:
- Investor — read-only across runway, financials, and aggregate KPIs. Cannot see customer PII anywhere on the platform.
- Co-founder — broad operator access, including runway as part of the financial picture.
- Super-admin — holds every permission including runway.
Plain admins, moderators, verifiers, and the finance role do not see this page. They're redirected to /dashboard if they try to open the URL directly. The page also doesn't surface in the admin tab strip; it shows up as a card on /admin (Quick Links → "Runway") for anyone whose role grants the permission.
The four KPI cards
The strip across the top is the at-a-glance read:
Monthly burn (USD). Sum of monthly_cost_usd across every vendor in tech_subscriptions whose status is not cancelled. This is the dollar-denominated half of our recurring spend — cloud bills, SaaS subscriptions, payment-rail fees that bill in USD. The sub-line shows active vs total vendor count so you can tell at a glance whether you're looking at "all 25 trackers" or "the 22 active ones".
Monthly burn (NGN-billed). Same idea, but for vendors that bill in Naira. We don't force an FX conversion to unify the two — the FX rate moves daily and would make the runway number wobble for reasons that have nothing to do with the business. Read the two cards together; the unified picture is in your head.
Revenue (30d, NGN). Recurring subscription payments + marketplace commission across the last 30 days. The sub-line breaks it down — Subs ₦X · Marketplace fee ₦Y — so you can see which lever is doing more work this month. Only succeeded subscription payments and completed marketplace orders count; failed charges and in-flight orders are excluded.
Runway months. Currently renders as a — placeholder. The arithmetic is straightforward (cash ÷ (burn − revenue)), but we don't yet have a cash_on_hand data source wired in — manual entry vs Monnify central balance integration vs treasury bookkeeping is an open product decision. The helper text under the card describes the manual computation if you want to do it yourself.
Vendor spend table
Every active vendor subscription, sorted by USD cost descending. Three columns:
- Vendor — the row's display name. If the underlying vendor brand differs from the display name (e.g. "Termii" vs the underlying BSP "360Dialog"), the brand is shown on a second line.
- Category — what we use the vendor for. Buckets: payments, comms, hosting, monitoring, etc.
- Status —
active(currently paying),pending_cancel(cancellation in progress with the vendor), or other lifecycle states. The colour-coding matches the convention on/admin/vendors. - Monthly cost — billed in whichever currency the vendor uses. USD vendors render as
$X; NGN vendors render as₦Y. Don't sum the column visually — the units don't match.
Use this table to spot which line items are driving the burn. If you want to drill into a single vendor (notes, contract renewal date, cancellation tracking), open /admin/vendors and click the row.
Recent subscription payments table
The last 10 successful subscription payments in the trailing 30 days, newest first. Three columns: when, tier, amount. If the window has more than 10 payments, a "+N more" footer surfaces the count.
This is the leading edge of the revenue line — every row here counts toward the "Revenue (30d, NGN)" KPI above. The "tier" column tells you the mix (mostly Growth signups, mostly Pro upgrades, etc.). If the table is empty, the runway page is correctly telling you that no one paid for a subscription in the last 30 days; that's a signal, not a bug.
What's deferred and why
The runway view is intentionally a v1. We chose to ship the measurable surface first and add depth as needs surface:
- Cash-on-hand input + automated runway-months calculation — needs a schema decision on how cash is tracked. Once that exists, the placeholder cell becomes a real number.
- Forward-looking projection — current view is the trailing 30 days; a 6-month projection chart needs either a finance-team forecast input or a simple "last-30d-rate × 6" extrapolation. We didn't ship the extrapolation because it's misleading without seasonality awareness.
- FX-rate normalised single-currency view — USD and NGN burn are shown separately on purpose. Forcing a conversion at a snapshot rate hides FX risk. A finance-grade view would carry both at all times plus the hedged scenario.
How to read the page in practice
A founder doing a weekly burn check: glance at the four KPI cards, eyeball whether the Revenue (30d, NGN) is roughly the same as last week, scroll the Vendor table for anything new or any "pending_cancel" row that's been there too long.
An investor doing diligence: read all four cards together with the vendor breakdown to verify the burn composition matches the pitch deck. Cross-check with /admin/insights (the aggregate KPI page) for the user-side picture.
A co-founder doing planning: use the page weekly as the source of truth for "what's our runway looking like?". The placeholder runway-months cell is the same conversation every week until a cash-on-hand input lands.
Related pages
/admin/vendors— full vendor subscription tracker. Add a new vendor, update a cost, mark cancellation confirmed. The Runway page is a read-only digest of what lives there./admin/insights— aggregate platform KPIs (signups, tier mix, marketplace volume, active users, geographic spread). The user-side picture that pairs with Runway's financial picture./admin/monnify— Monnify wallet float, off-band movements, reconciliation. The cash-side reality that an eventual cash-on-hand input would source from.
Where the data comes from
tech_subscriptionstable — vendor list + monthly costs (USD + NGN)subscription_paymentstable — recurring revenue (filtered to statussucceededover the trailing 30 days)marketplace_orderstable — commission revenue (filtered to statuscompletedover the trailing 30 days)
All three are server-rendered fresh on every page load; there's no cache between you and the database. Refreshing the page is the same as reloading the data.

