Skip to content

Router.Africa — Dashboard Scope

Backlog item #3 (product half — stack half is resolved in the Tech Stack doc). What the dashboard actually needs: screens, data, and actions. Each ties back to something already decided elsewhere in the architecture, noted per section.


  • Sign up / log in — email+password and social login (Better Auth, per the Dashboard Auth decision). Social login is a stated hard requirement, not optional.
  • Session management — logout, and logout-everywhere if a session-revocation need comes up later.

No org/team/multi-user screens for now — the architecture assumes single-account-per-API-key (noted as a premature feature if built now, per the tech stack doc’s “explicitly not adopted” list). Revisit if that assumption changes.


First thing a logged-in user sees. Pulls from the areas below rather than owning new data itself:

  • Current credit balance
  • Quick usage snapshot (e.g. last 24h requests, spend)
  • Any account-level alerts (e.g. low balance)

  • Requests/spend over time, filterable by model and date range
  • Cost breakdown by model/provider
  • This is read data from the async analytics pipeline (Cloudflare Queues → apps/dashboard-api → analytics store) — inherently near-real-time, not instant, given the pipeline is deliberately async. Worth the UI reflecting that (e.g. “as of a few minutes ago”) rather than implying live data.

  • Per-request detail: timestamp, model, status, latency, tokens, cost
  • This is the same logged metadata decided under Request Logging in the architecture — the dashboard is simply the read view onto it.
  • Filterable by API key, model, date range, status.

  • List, create, revoke, rotate keys.
  • Per-key spend cap — already decided as part of API key security (bounds blast radius on a leak).
  • Rate limit (set per org)admin-only, not customer-facing. Not a field on this screen; Router.Africa sets and manages it internally, invisible to the account holder. Stored in Postgres and enforced by Bifrost via the key’s 1:1 virtual key.
  • Model availability per key — a customer chooses which models are enabled for each key (scoped per key, decided). Starts at signup for the first key (see Onboarding below), but is editable here too, not just a one-time onboarding step.
  • Key display follows the security decision already made: raw key shown once on creation, never again (only the stored hash exists after).

  • Current balance, including any active holds (so a customer isn’t confused why available balance is lower than expected mid-request).
  • Published rate visibility — the daily per-model, per-token-type rate, shown as the final rate only — no breakdown of base cost, FX, or markup. A single clean number per the Pricing Model doc’s transparency requirement (“customers see THAT as the cost… at any time”), not a cost-composition view.
  • Top-up flow — via Niobi payments, routed through apps/niobi-proxy. This is the one flow that talks to a real external payment provider — needs the usual careful UX around pending/failed/succeeded states, not just happy path. The customer enters the credits they want, sees the transaction fee and total to pay (e.g. 1,000 credits + 40 fee = 1,040) before confirming, and only the credits are added to their balance. Fee values are managed in the admin app.
  • Transaction history — settlements, top-ups, holds released.

  • Basic profile/email management
  • Prompt/response retention opt-out — on by default; a customer can opt out of Router.Africa saving their prompts and data (see the Decisions Log, Audit trail & prompt/response retention)
  • Password/social login management (whatever Better Auth’s own UI primitives support — worth checking what it provides out of the box before custom-building this)

Signup → first API key must be fast — this is the stated priority, not a nice-to-have. Minimize steps between account creation and having a working key in hand; every screen between signup and “here’s your key” is a drop-off risk.

Model selection is part of this flow — the customer chooses which models are enabled for their account/key during onboarding (and can revisit this later under API Keys, per above). This is more than a UI step: it implies an allowed-models list needs enforcing on the backend, not just displayed on the frontend — apps/api needs to check the requested model against the account’s/key’s allowed list before routing to Bifrost, and reject or fall back appropriately if a model outside the selection is requested. This is a new item for backend scope (#4) and schema (#6) — an allowed_models field (per key, decided) needs to exist and be checked in the request path, alongside the hold/idempotency/rate-limit transaction already decided.

Concrete flow, subject to refinement once backend scope is drafted:

  1. Sign up (email or social)
  2. Select models to enable (sensible defaults pre-checked, so this isn’t a blocking decision — a customer can accept defaults and move on immediately)
  3. Key generated automatically, shown once
  4. Land on Overview/quickstart

  • None currently. Model selection: per-account or per-key? was resolved — per key (see the Decisions Log).

Cross-reference the Decisions Log for the backend behavior each screen surfaces, and the Pricing Model doc for the billing screen’s rate display requirement.