cases and backend
Swap Support — Cases & Backend
Section titled “Swap Support — Cases & Backend”Author: Ridwan Egbeyemi (PM, Swap) Date: 18 May 2026
The 16 operational scenarios we’ve designed for, and the backend services needed to power resolution across the swap app (station manager) and Atlas (support specialist / PM).
1. Scenarios breakdown
Section titled “1. Scenarios breakdown”| # | Scenario | Captured in the swap app | Resolved in Atlas | Severity |
|---|---|---|---|---|
| Station | ||||
| 1 | Temporary swap (away from primary station) | Inline alert on rider profile · request authorization · park while support decides | Three decisions: allow + ₦500 fee · allow + waive fee · deny (rider returns to primary) · pattern flag if 3+/week | Med |
| 2 | Primary station change | Initiated from support page · scan/license lookup → 2-step form → pending status → approval push | Approve/deny · both stations & rider notified · effective immediately or scheduled | Low |
| Wallet & payments — scenarios 4, 6, 7, 8 share one entry point: the “How is the rider paying?” alert on the rider profile (4 actions: pay from station wallet · show funding accounts · log rider’s receipt · funds at another station). The four backend paths below remain distinct. | ||||
| 3 | Wallet not loading | Inline alert · retry · park while support rebuilds record | Force wallet rebuild from ledger · push manager when ready | Med |
| 4 | Insufficient balance | Consolidated alert · “Show funding accounts” opens Opay / Paystack / Monnify | n/a — resolves itself when funds arrive | Med |
| 5 | Daily-fee deduction fails | Manager taps “Draw daily fee”, service rejects · retry · send to support | Engineering follow-up · safe retry (idempotent · no double-charge) | Med |
| 6 | Funding not reflecting | Consolidated alert · “Log rider’s receipt” opens reconcile sheet · single OR multiple payments · virtual-account + source-bank pickers | Live settlement-feed tail · one-time overdraft / wait / deny | High |
| 7 | Station-wallet subscription payment failed | Consolidated alert · “Pay from station wallet” then transfer fails · retry · escalate to support | Confirm engineering fix · retry transfer on station’s behalf | Med |
| 8 | Funds at another station | Consolidated alert · “Funds at another station” opens dispute sheet · photo evidence + manager picker | Click-to-call both managers · move ₦12,000 from station A’s wallet → rider wallet · resolve | High |
| 8a | Funding account number invalid | Consolidated alert · “Funding account invalid” opens capture sheet (provider · shown account number · rider bank error) · waiting card · resume push when fixed | Support escalates internally to engineering to compare provider-generated account vs what the rider sees · audit captures the affected VA and provider | Med |
| Battery — every battery issue traces back to a single root cause: a field-support staff did a swap without using the app, so both batteries (old + new) end up with the wrong digital position. That single off-app swap surfaces as up to three downstream scenarios (9, 10, 11) on later swaps. Scenario 16 is a separate problem — a typo/worn printed serial that returns no inventory data when scanned. Scenarios 9/10/11 resolve with a single-click record mutation in Atlas (no relabel). Only 16 keeps the print-and-stick mechanic. | ||||
| 9 | Release-and-reassign (old battery) | Inline alert on scan-new-battery · “Send to support” → captured-context sheet (rider · scanned serial · last-known keke) · waiting card · resume push when released | Support reviews + calls manager · one click releases the battery from the previous rider and reassigns it to this station · audit captures the actor + delta | Med |
| 10 | Station claim (new battery) | Inline alert on scan-new-battery · “Send to support” → captured-context sheet (where system thinks it is) · waiting card · resume push when claimed | Support reviews + calls manager (and other-station manager when relevant) · one click claims it for the calling station · audit captures the inter-station transfer | Med |
| 11 | Old-battery attribution (rider) | Empty-state on the VCU “Current battery in keke” card · “Send to support” → captured-context sheet (rider + keke history) · waiting card · resume push when attributed | Support reviews keke history + calls manager · one click attributes a candidate old-battery serial to the keke · swap-app refreshes the VCU card so the manager can advance | Med |
| 16 | Serial mismatch (new battery) | Inline alert on scan-new-battery — scanned serial returns no data · “Send to support” → captured-context sheet · waiting card · ready card with corrected serial · manager copies, prints, sticks, rescans (validated against corrected serial) | Support finds the closest match in inventory and pushes the corrected serial back; audit records the relabel; rescan mismatches captured separately | Low |
| VCU connection | Scenarios 12 / 13 / 14 deferred — bluetooth pairing stays in the swap app, but the unlock-fail / internet-fallback / manual-code path is being redesigned to live entirely in-app (no support specialist in the loop). Until that design lands these are not surfaced in the backoffice. | |||
| Next-day follow-up | ||||
| 15 | Outstanding overdraft blocks new swap | Inline danger alert on rider profile · single CTA “Open case ISS-XXXX” · no manager override | Atlas Ops must reconcile against late settlement, or write off the prior swap, before another is permitted | High |
Numbering: battery group went from 2 → 4 — 9/10/11 are the three downstream surfaces of the same off-app-swap root cause; 16 is the standalone serial-mismatch path. VCU connection still covers three distinct paths through the same screen; #15 is the next-day consequence of an unreconciled #6.
2. Backend services required
Section titled “2. Backend services required”Eight services are needed end-to-end. Some exist today; most need to be built or extended.
2.1 Rider wallet service
Section titled “2.1 Rider wallet service”- Balance, debit, credit (all idempotent — keyed by
swap_idortxn_id). - Support for overdraft with auto-reconciliation against the next inbound settlement.
- Overdraft eligibility guardrail. The
overdraft_creditendpoint must reject requests unless the originating case type is in the wallet group (funding-not-reflecting, funds-at-another-station, station-wallet-payment-failed, daily-fee-deduction-failed, funding-account-invalid). A case ID is mandatory on every overdraft call and the server cross-checks the case type before crediting. The Atlas UI mirrors this with an explicit “case eligible · confirm” checkbox; the “Issue overdraft” button stays disabled until the support specialist ticks it. Closes the loophole from the 17 May incident where an overdraft was credited to a rider whose case had no wallet need. - Outstanding-overdraft flag that survives across days: while a prior overdraft is unsettled, the wallet exposes
swap_eligible: falsewith a pointer to the originating case. Swap-app reads this on every scan and blocks the swap at the rider-profile step until Ops reconciles or writes off. Powers scenario 15. - Read API streams to swap-app on every screen that surfaces wallet state.
- Powers scenarios 3, 4, 5, 6, 7, 8, 15.
2.2 Station wallet service
Section titled “2.2 Station wallet service”- Each station has a wallet balance. The on-duty manager operates it; ownership and reconciliation belong to the station, not the individual operator.
- Station wallet → rider subscription payment (idempotent, atomic, with reversal hooks).
- Cross-station transfer (debit station A’s wallet, credit rider’s wallet at station B) — powers scenario 8.
- Powers scenarios 4 (station-pays path), 7, 8.
2.3 Virtual account settlement ingest
Section titled “2.3 Virtual account settlement ingest”- Webhook + polling endpoints for Opay, Paystack, Sterling.
- Match inbound transfers to rider phone numbers / sender accounts.
- Live tail visible to support in Atlas for the funding-not-reflecting flow.
- Store: virtual account hit, sender bank, amount, timestamp, rider-match confidence.
- Powers scenarios 4 (funding path), 6. The sender-bank field is the dataset for “which banks settle slowest?” reports.
2.4 Inventory service (batteries)
Section titled “2.4 Inventory service (batteries)”- Battery serial → current location mapping. Location is either a station, a keke, a charge-hub, or in-transit between any two.
- States:
at-station,in-transit,in-keke,at-charge-hub,quarantined. - Release-and-reassign endpoint — atomically detach a battery from a previous keke and attach it to a station. Powers scenario 9. Idempotent on
(battery_serial, target_station_id). - Station-claim endpoint — atomically move a battery from its current (incorrect) location to the calling station. Same shape as release-and-reassign but does not require a “from-keke” — the from-side can be another station or another keke. Powers scenario 10.
- Old-battery-attribute endpoint — assign a candidate battery serial to a keke that has no current battery on record. Used when the rider arrives and the VCU pair returns no current-battery info. Powers scenario 11.
- Issue-corrected-serial endpoint — when a manager scans a new battery and the serial returns no data (typo / worn / off-by-one printed label), support reviews and pushes back the closest matching
BP-YYMMDD-NNNNNNNNserial. Manager copies, prints, sticks; subsequent scan is validated against the issued serial. Mismatches are captured for audit. Powers scenario 16. - All four endpoints write audit entries with the support actor, the manager, both location records (before/after), and the originating case ID.
- No record is ever delisted; corrections move position only. The bad-position population dies out over time as future swaps trigger these flows.
- Powers scenarios 9, 10, 11, 16.
2.5 Station & manager registry
Section titled “2.5 Station & manager registry”- Station record (location, type, capacity, opening hours).
- Manager record (name, phone, current station, station-wallet balance).
- Rider → primary station assignment with history (for primary-change requests).
- Powers scenarios 1, 2, 8 (and the contact-card click-to-call data everywhere in Atlas).
2.6 VCU command bus (scope reduced)
Section titled “2.6 VCU command bus (scope reduced)”- Bluetooth route (mobile-app-initiated, low-latency) — the pairing that the manager runs at every swap.
- Internet / manual-unlock fallbacks deferred — the team is redesigning the unlock-fail path to live entirely in-app, with no support specialist in the loop. Until that design lands, the backoffice carries no VCU resolution surface.
2.7 Support case service
Section titled “2.7 Support case service”- Case state machine:
open → in-progress → pending-external → resolved | denied | escalated. - Routing: round-robin within severity weight, with SLA timers.
- Issue typing — each of the 16 scenarios above has a canonical case type.
- Linked engineering tickets (for scenarios 5, 7).
- Powers everything in Atlas — queue dashboard, issue detail, resolution actions.
2.8 Audit trail service
Section titled “2.8 Audit trail service”- Append-only log: every approve / deny / transfer / call / note / code-issue / retry by every staff member.
- Captures
actor, action_type, target, delta, timestamp, linked_case_id, internal_note. - Query API filterable by staff, action type, issue type, time window — powers both Tunde’s “My audit trail” and Ridwan’s PM dashboard team feed & anomaly detection.
- Immutable — no edits, no deletes; corrections are new entries that reference the original.
3. Cross-cutting concerns
Section titled “3. Cross-cutting concerns”Idempotency
Section titled “Idempotency”Every money-moving action (wallet debit, manager transfer, overdraft credit, daily-fee draw, retry of a failed transfer) must accept a client-generated idempotency key. Retries with the same key return the original result; never double-charge.
Notifications
Section titled “Notifications”Push to manager phone (deep-linking back into the swap), in-app notification banner for the parked-swap resume flow. Triggered by: case-resolved, funding-arrived, ops-approved, code-issued. Audit-trail entries are written first, notification fires second.
Real-time hooks
Section titled “Real-time hooks”- Swap-app polls
GET /v1/wallet/balanceevery 30s when a parked swap is active, so the resume push can be triggered from inbound settlement. - Atlas streams the settlement feed via SSE / WebSocket for the support specialist’s live reconciliation view (scenario 6).
SLAs (proposed, need leadership sign-off)
Section titled “SLAs (proposed, need leadership sign-off)”- Urgent in-swap blockers (funding-not-reflecting, funds-other, daily-fee-fail): 5–15 min.
- Medium (wallet-fail, battery-transfer, manager-top-up-fail): 15 min.
- Low (primary-change, battery-conflict-audit): 24 h.
Click-to-call
Section titled “Click-to-call”Atlas dialer routes through the support specialist’s soft-phone (Twilio/Africa’s Talking). Number-of-calls and call-duration are written to the audit trail automatically — no user action needed.
4. Service ↔ scenario matrix
Section titled “4. Service ↔ scenario matrix”For engineering scoping, which services each scenario touches:
| Scenario | Rider wallet | Stn wallet | VA ingest | Inventory | Stn/mgr registry | VCU bus | Case svc | Audit |
|---|---|---|---|---|---|---|---|---|
| 1 Temp swap | ● | ● | ● | |||||
| 2 Primary change | ● | ● | ● | |||||
| 3 Wallet not loading | ● | ● | ● | |||||
| 4 Insufficient balance | ● | ● | ● | ● | ● | |||
| 5 Deduction fails | ● | ● | ● | |||||
| 6 Funding not reflecting | ● | ● | ● | ● | ||||
| 7 Mgr top-up failed | ● | ● | ● | ● | ||||
| 8 Funds at another stn | ● | ● | ● | ● | ● | |||
| 9 Release & reassign (old) | ● | ● | ● | ● | ||||
| 10 Station claim (new) | ● | ● | ● | ● | ||||
| 11 Old-battery attribution | ● | ● | ● | ● | ||||
| 16 Serial mismatch (new) | ● | ● | ● | |||||
| 15 Overdraft pending | ● | ● | ● |