Skip to content

PRD

Author: Ridwan Egbeyemi (PM, Swap) Status: Spec-locked · ready for engineering Surfaces: Rechaj Swap (mobile) · Atlas (web) Prototype references: products/rechaj-swap-app/prototypes/support-cases-v3.html · products/atlas/prototypes/swap-support-resolution.html Supersedes: specs/2026/swap-support/ — earlier iteration. Where this PRD’s issue taxonomy or officer-role model conflicts with the older doc, this PRD wins.


Today, swap managers escalate operational issues to Rechaj support over WhatsApp. Nothing is tracked, managers sit blocked while riders queue behind them, and officers copy details by hand from WhatsApp into Atlas — which on 17 May caused an overdraft to be credited to the wrong rider. This PRD replaces WhatsApp end-to-end with structured in-app support: managers report issues from inside Rechaj Swap, tied to the active swap; officers resolve them inside Atlas against context that was captured at report time, never re-typed; both sides share the same issue record and message thread; every action is logged.


  • Eliminate copy-paste resolution actions. 100% of resolution forms in Atlas open with rider, wallet, battery, transaction, bank, and account identifiers pre-loaded from the issue payload. Zero free-text rider-ID entry on any resolution action. Closes the wrong-rider incident class structurally.
  • Replace WhatsApp. ≥95% of support traffic flows through the in-app system within one month of GA. WhatsApp escalations drop to a fallback for app-down incidents only.
  • Preserve swap throughput under blocking issues. A manager who parks a stuck swap can complete ≥3 subsequent swaps for other riders without losing the parked swap’s context, and resumes it on push without re-entering identifiers.
  • Measurable resolution times per issue type. [Derived] Median time-to-acknowledge < 2 min; median time-to-resolve < 10 min for the highest-volume issue types (3.1 Release & Reassign, 3.2 Station Claim, 2.1 Payment not reflecting). Confirm targets with leadership (Q1).
  • Officer-type routing accuracy. Issues land in the correct officer-type queue on first submission with no manual triage. Issue type → owner mapping is enforced server-side, not by UI convention.
  • Auditability. Every resolution action, escalation, and message exchange writes an immutable audit entry with actor, target, before/after delta, timestamp, and case ID.

  • Penalty system for temporary station requests (issue 1.1). Data model must anticipate it; logic ships later.
  • Facility BU issue resolution. Facility Officer role exists for RBAC scaffolding; no issue types route to them in this release.
  • Energy BU resolution. Role model must extend cleanly; nothing is built for them now.
  • WhatsApp fallback. No bridge, no integration, no parallel pathway. The system replaces WhatsApp; it does not coexist with it.
  • AI-assisted resolution / smart routing / sentiment-based prioritization. Out of scope.
  • Gamification of feedback ratings. Ratings inform ops; they do not score managers or unlock features.
  • VCU connection scenarios (former scenarios 12 / 13 / 14). Deferred per the swap-support/overview.md decision; the in-app unlock redesign supersedes any officer-in-the-loop path.

Role Surface Resolves issue types Notes
Swap manager Rechaj Swap (mobile) — Reports issues. Receives clarifications, sends evidence retakes, gets push when resolved.
Swap Support Officer Atlas 1.1, 1.2, 2.1, 2.2, 2.3 (passive), 3.1, 3.2, 3.3 Owns the bulk of the queue. Escalates 2.4 / 2.5 / 3.4.
Payment Officer Atlas (none in this release; receives wallet escalations) [Derived — confirm in Q2: which 2.x issues, if any, should route to Payment Officer directly vs flow through Swap Support first?] Models the BU separation for future routing.
Engineering Support Officer Atlas 2.4 Phantom pending swap fee · 2.5 Invalid funding account Receives escalations from Swap Support; loops in engineering off-platform.
Inventory Support Officer Atlas 3.4 Serial Mismatch Receives escalation.
Facility Officer Atlas — RBAC-only in this release. No resolution surfaces.
Future BU officers (Energy, etc.) Atlas — Role model must extend without schema changes.

A single human user may hold multiple officer roles simultaneously. RBAC checks at the action layer, not the page layer — a Payment + Swap Support officer sees both queues merged in their inbox with a per-row officer-type tag.


Pain point Today (WhatsApp) After this release
Where issues live Officer WhatsApp threads, scrollback, screenshots. Atlas queue, one record per issue, full thread visible to both sides.
What context the officer sees Whatever the manager remembers to type. Full payload: rider, wallet, battery, transaction, bank, station, manager, timestamp — captured at report time, never re-typed.
How a stuck rider stops blocking Doesn’t. Manager and rider both wait. Manager parks the swap, serves the next rider, returns to the parked swap on push.
How wrong-rider mistakes happen Officer copies “Adekunle, 080…” from WhatsApp, mistypes the wallet ID, hits Issue Overdraft. Resolution actions take only the loaded case payload as input. Rider/wallet/battery IDs are not editable on resolution.
How re-requests for clearer evidence work “Please send a clearer photo” in WhatsApp; the new photo lands in a different thread or DM. First-class re-request loop in the issue thread. New uploads attach to the same issue record. v1/v2 version chips render in Atlas.
How escalation between teams works Officer forwards the WhatsApp thread or @-mentions another team. Hand-off is lossy. One-click route handoff. Receiving officer-type queue inherits the full record + thread; originating officer can view but no longer resolve.
What the PM can see Nothing aggregate. Volume by issue type, by officer, by station; time-to-resolve distributions; rejection / clarification ratios.

Each issue type follows the same template: trigger · report-side flow · required fields & evidence · resolve-side flow · owner · escalation · edge cases · acceptance criteria.

Existing prototype screens are cited where they map.

  • Trigger. Rider attempts a swap at a station that is not their primary; alert fires on the rider-profile step of Rechaj Swap (alert-mismatch inline on screen-tricycle-detected).
  • Report-side flow (Rechaj Swap). Manager taps Request authorization in the inline alert → sheet sheet-station opens with rider/plate/station pre-filled → manager picks a reason chip (Battery emergency · Customer en route · Station closed · Other → Tell support… textarea + voice note) → submits. Swap auto-parks on submit; manager serves next rider.
  • Required fields. Reason chip; if Other, free-text or voice note. All identifiers pre-populated.
  • Resolve-side flow (Atlas). screen-issue-temp-swap opens with rider context, primary-vs-current station, temp-swap history (count this week). Officer picks Approve / Deny.
  • Owner. Swap Support Officer.
  • Escalation. None in this release.
  • Edge cases. Rider’s primary is the same as the current station (issue should not be raisable). Same rider raises ≥3 temp requests in 7 days — flag visible on the resolution screen, no auto-action. [Derived] Auto-deny if rider has an unresolved overdraft (links to 2.2) — confirm in Q3.
  • Acceptance criteria.
    1. Sheet pre-fills rider name, plate, primary station, current station without manager input.
    2. Submission triggers swap park; manager can start a new swap immediately.
    3. Atlas screen shows temp-swap history count for the rider in the last 7 days.
    4. Approve triggers push to manager; manager resumes the parked swap and the alert is gone.
    5. Deny triggers push with the officer’s reason; resumed swap shows a “cancel · rider returns to primary” state. [Derived]
    6. Data model captures intent: temporary so a future penalty rollup can compute counts per rider per period without a schema change. [Derived]
  • Trigger. Manager initiates from the Rechaj Swap support log: Quick request → Reassign primary station (screen-perm-change-lookup).
  • Report-side flow. Manager scans rider’s keke QR or enters plate + phone → confirms identity → 2-step form: select new primary (auto-suggests current station) + reason chip + optional note/voice → submits → screen-perm-change-status shows pending state.
  • Required fields. New primary station; reason chip; optional rationale.
  • Resolve-side flow (Atlas). screen-issue-perm-change shows rider, current primary, requested primary, distance from rider’s address, recent temp-swap count, manager’s reason. Officer picks Approve immediately / Approve effective next Monday / Deny + reason.
  • Owner. Swap Support Officer.
  • Escalation. None.
  • Edge cases. Same-station request must be rejected at submit. Same rider requests ≥1 reassignment / 30 days — flag in Atlas; allow override. [Derived — see Q4: cooldown policy.] Approval ≠ same as immediate state change if scheduled for later.
  • Acceptance criteria.
    1. Manager cannot submit if requested primary equals current primary.
    2. Atlas resolution shows recent temp-swap pattern as decision context.
    3. Approve writes the new primary; manager sees confirmation push; future temp-swap alerts no longer fire for this rider at the new primary.
    4. Effective-date supported: Approve-immediately vs Approve-scheduled.
    5. Audit entry captures previous primary, new primary, scheduled-vs-immediate flag, officer ID, manager ID, rider ID.

Baseline behaviour: the first swap of the day debits the daily subscription (currently ₦12,000) from the rider wallet; subsequent swaps the same day show “Paid” / ₦0. All wallet flows enter through the “How is the rider paying?” consolidated alert on the rider-profile step (alert-payment in support-cases-v3.html), with Wallet history accessible from the wallet hero on every wallet-state screen.

  • Trigger. Rider claims to have transferred funds; wallet still shows insufficient balance.
  • Report-side flow. “How is the rider paying?” → Log rider’s receipt opens sheet-reconcile → manager picks Single / Multiple payments → per-payment: amount (only; sent-at is dropped per design rule) + virtual account (Opay / Paystack / Monnify) + sender bank + photo of receipt (take or upload) → submits.
  • Required fields per payment. Amount, destination virtual account, sender bank, receipt photo. Yellow callout pre-submit reminds the manager that the transaction reference or session ID must be readable.
  • Resolve-side flow (Atlas). screen-issue-funding-pending opens with: large receipt preview at top (480px), version chips (v1, v2 if retaken), claimed amount, destination VA, claimed sender + bank, rider wallet activity (last 7 days), and an “Action” select. Resolution form requires the officer to pick Transaction reference vs Session ID (radio), then paste the value from the receipt into a single input. Officer ticks the overdraft eligibility confirmation, then taps Issue overdraft & resolve to credit ₦12,000 against the pasted reference. Credit is reconciled later by the settlement matcher.
  • Owner. Swap Support Officer (with overdraft-eligibility guardrail on the wallet service, enforced server-side; UI checkbox mirrors the check).
  • Escalation. None — receipt re-request loop replaces escalation. If the receipt is unclear: officer types a reason in the inline “Receipt unreadable?” block (which sits directly under the reference field) → taps Send back · request clearer receipt → manager receives a push, opens the support thread on the swap app side as a full-page sheet, taps the previously uploaded photo to view, then taps Reupload photo to retake → v2 chip lands in Atlas, preview swaps, thread captures both turns.
  • Edge cases.
    • Multiple payments claimed: each is a slot in the reconcile sheet; the officer can issue one overdraft per payment, all linked to the same case.
    • Photo retake count is unbounded; each becomes a new version chip.
    • Receipt reference duplicates an existing settlement match — wallet service must reject the overdraft as already-credited (idempotency on reference field). [Derived]
  • Acceptance criteria.
    1. Manager cannot submit without at least one receipt photo per payment slot.
    2. Atlas resolution refuses to issue an overdraft if the eligibility checkbox is unticked OR the radio choice + reference field is empty.
    3. “Send back” triggers a manager push within 10s; manager’s reupload appears as v2 in Atlas within 5s of upload completion.
    4. Resolution writes one wallet credit per overdraft, keyed by the reference value (idempotent).
    5. Audit entry captures case ID, officer ID, reference value, reference kind (transaction-ref / session-id), and overdraft amount.
  • Trigger. Rider scans for a swap; rider wallet exposes swap_eligible: false because a prior overdraft (from 2.1) has not yet been reconciled by inbound settlement. Inline danger alert fires (alert-overdraft-pending).
  • Report-side flow. Send to support opens sheet-overdraft-pending → manager re-uploads the receipt of the unsettled payment (with the same clarity expectation as 2.1) → submits.
  • Required fields. Receipt photo. Case ID is not shown to the manager; it stays internal. (See the no-tech-codes rule.)
  • Resolve-side flow (Atlas). Officer reviews the receipt and the rider’s wallet activity; if the inbound credit has now landed, the officer lifts the overdraft ban so the rider can swap. If still missing, the officer can keep the ban + send back for clarification.
  • Owner. Swap Support Officer.
  • Escalation. None.
  • Edge cases. Same rider’s wallet activity already shows a successful settlement that the eligibility flag missed — officer can lift directly without an overdraft action. [Derived]
  • Acceptance criteria.
    1. The rider profile shows the overdraft alert with no manager override path (Send to support is the only CTA).
    2. The resolution surface shows the originating 2.1 case linked, plus current wallet activity.
    3. Lifting the ban writes swap_eligible: true immediately; manager receives a push; the next scan succeeds.
    4. Audit captures the lift action, prior ban reason, case linkage.
  • Trigger. Rider scans; wallet is ₦0 and no prior overdraft. Manager surfaces the consolidated alert.
  • Report-side flow. “How is the rider paying?” → Show funding accounts opens sheet-payment showing the rider’s virtual accounts (Opay primary, Paystack, Monnify) with copy-to-clipboard. No officer interaction by default; the manager parks the swap to serve other riders. Resolves when the wallet shows ≥₦12,000 (poll/push).
  • Required fields. None — no support officer involved.
  • Resolve-side flow (Atlas). No queue entry by default.
  • Owner. Self-resolving.
  • Escalation. Manager can convert to a 2.5 (Invalid funding account) report if the rider says the account number is being rejected.
  • Edge cases. Wallet credit arrives while swap is parked → push resume.
  • Acceptance criteria.
    1. Funding accounts sheet pulls the rider’s virtual accounts via the wallet/account service; no manager input.
    2. While parked, wallet polls every 30s for balance ≥ daily fee; on threshold, push fires and resumed swap auto-advances.
    3. No support case is created unless the manager escalates to 2.5.
  • Trigger. Rider has already completed at least one swap today (subscription debited; subsequent swaps should be “Paid · ₦0”); on a later swap the wallet hero wrongly shows a fee owed.
  • Report-side flow. “How is the rider paying?” → Rider had previously paid today → sheet-previously-paid opens with rider context and an inlined snapshot of today’s prior swap fee debit + subsequent free swap, with prose: “If you see today’s debit here, send to support to clear the duplicate fee” → manager submits.
  • Required fields. Rider context is auto-attached. No additional input required from the manager beyond the submission tap; the wallet history inline confirms the manager’s claim.
  • Resolve-side flow (Atlas). [Derived screen — to be built. Tentative ID: screen-issue-phantom-fee.] Officer reviews the rider’s full wallet history (read-only). Cannot resolve; Escalate to Engineering Support Officer is the primary action. Engineering loops in the platform team off-platform; once engineering reports the fix is in, Swap Support officer alerts the manager via the thread; manager re-attempts the swap.
  • Owner. Swap Support Officer triages; Engineering Support Officer resolves.
  • Escalation. Mandatory: Swap Support → Engineering Support.
  • Edge cases. Re-occurrence on the same rider within 24h after a “fix landed” — re-open the escalated case instead of creating a new one. [Derived]
  • Acceptance criteria.
    1. The “Rider had previously paid today” button is only shown when the wallet-short consolidated alert is visible.
    2. Submission creates a case with type phantom-fee; routing assigns to Swap Support’s queue first.
    3. Atlas resolution view shows wallet history with today’s earlier swap fee debit highlighted; Resolve is disabled, Escalate to Engineering is enabled.
    4. Escalation moves case ownership to Engineering Support queue; original officer retains read access.
    5. Engineering’s mark-fixed action writes a thread message and a push to the manager.
  • Trigger. Rider’s virtual funding account (Opay / Paystack / Monnify) is being rejected by the rider’s bank (the destination account number does not return a beneficiary name).
  • Report-side flow. “How is the rider paying?” → Funding account invalid opens sheet-acct-invalid → manager picks affected provider (Opay / Paystack / Monnify; no “Other”) → enters the account number shown to the rider → takes/uploads photo of the error on the rider’s screen → submits.
  • Required fields. Provider chip, account number shown, screen-error photo.
  • Resolve-side flow (Atlas). [Derived screen — to be built. Tentative ID: screen-issue-acct-invalid.] Officer reviews provider + shown number + screenshot. Cannot resolve; Escalate to Engineering Support Officer.
  • Owner. Swap Support Officer triages; Engineering Support Officer resolves.
  • Escalation. Mandatory: Swap Support → Engineering Support.
  • Edge cases. The same provider + account shows up in multiple manager reports within 1 hour — flag in Atlas as a likely platform-wide outage. [Derived]
  • Acceptance criteria.
    1. Sheet refuses to submit without the screen-error photo.
    2. “Other” is not in the provider chip list.
    3. Atlas escalation routes to Engineering Support; Engineering’s mark-fixed action writes a thread message and a push to the manager.

Per the battery-photo-required rule, every battery case requires the manager to upload a clear photo of the physical battery’s serial sticker. Every battery case supports the same retake loop as 2.1.

  • Trigger. Manager scans a battery to issue to a rider; app shows the battery is digitally attached to a different keke (off-app field swap left a stale record).
  • Report-side flow. Inline alert on screen-scan-new-battery → Send to support opens sheet-battery-release with the scanned serial, rider, plate, current digital holder (rider name + plate as a small pill, per the keke-identity rule), this station, manager. Manager attaches a photo of the physical battery; submits.
  • Required fields. Battery photo. All identifiers auto-attached.
  • Resolve-side flow (Atlas). screen-issue-battery-release opens with photo evidence (large preview + version chips), conversation thread, calling station, current digital holder. Officer’s primary action: Release & reassign · resolve — one-click record mutation. Send-back-for-clearer-photo CTA in the resolution card.
  • Owner. Swap Support Officer.
  • Escalation. None.
  • Edge cases. Photo unreadable → send back; v2 lands in the thread and as a new version chip.
  • Acceptance criteria.
    1. Submission attaches the battery serial as the case key; idempotent on (case_id, action).
    2. Resolution flips the inventory record atomically: detach from previous keke, attach to calling station.
    3. Resume push fires to the manager; manager’s swap app shows the resolved alert and proceeds.
  • Trigger. Manager wants to digitally claim possession of one or more physical batteries that are at their station but recorded elsewhere.
  • Report-side flow. From the support log: Quick request → Battery transfer (sheet-battery-transfer) → for each battery: tap the QR-scan affordance (opens a camera-overlay scanner — reticle + scan line; locks on after ~1.6 s and commits the serial) + photo of the physical battery + optional notes; manager can add multiple battery slots in one submission → submits. Each battery becomes one issue record (parallel cases), all linked to one submission for the manager’s view.
  • Required fields per battery. Serial (via scanner or typed); photo.
  • Resolve-side flow (Atlas). screen-issue-battery-claim for the single-battery scan path; screen-issue-battery-transfer for the manager-initiated multi-battery path (current location, calling station, photo evidence per battery). Per-battery one-click claim.
  • Owner. Swap Support Officer.
  • Escalation. None.
  • Edge cases. A battery in the submission is currently with another keke digitally → force-claim is allowed; the other keke’s next swap surfaces as 3.3, which self-heals (per the battery-cause framing in swap-support/overview.md).
  • Acceptance criteria.
    1. Each battery in a multi-battery submission produces one independent case.
    2. Atlas displays the per-battery photos as thumbnails, each clickable to full size.
    3. Resolving one battery in a multi-battery submission does not affect the others.
  • Trigger. Rider arrives with a depleted battery whose serial doesn’t return a current record after VCU pair (the previous swap was not recorded).
  • Report-side flow. Empty state on the VCU connected pane shows “Battery serial not on record” → Send to support opens sheet-battery-attribute (sheet name preserved for code continuity; user-facing language is assignment, per the assignment-not-attribution rule) → manager attaches a photo of the physical battery’s serial sticker; submits.
  • Required fields. Battery photo. Rider, plate, station pre-attached.
  • Resolve-side flow (Atlas). screen-issue-battery-attribute with photo + thread (currently shows v1 rejected / v2 current as the canonical demo). Officer reads the serial from the photo, enters it in the resolution field, taps Assign serial · resolve. Send-back-for-clearer-photo CTA in the resolution card.
  • Owner. Swap Support Officer.
  • Escalation. None.
  • Edge cases. Photo unreadable → retake loop. Officer reads a serial that’s not in inventory at all → escalate as 3.4. [Derived]
  • Acceptance criteria.
    1. The empty-state card is only shown when VCU pair returns no current battery; the inline alert blocks the unlock toggle until support assigns a serial.
    2. Resolution writes the assignment atomically; manager’s VCU card refreshes with the assigned serial; the unlock toggle becomes available.
    3. Send-back appends a support message to the thread immediately and simulates the retake loop end-to-end.
  • Trigger. Manager scans a new battery; the serial returns no inventory data (typo / worn label / off-by-one print).
  • Report-side flow. Inline alert on screen-scan-new-battery → Send to support opens sheet-battery-mismatch with the scanned serial + photo of the physical battery → submits.
  • Required fields. Battery photo. Scanned serial auto-attached.
  • Resolve-side flow (Atlas). Swap Support Officer reviews; cannot resolve — escalates to Inventory Support Officer. Inventory officer searches inventory manually (no auto-suggested closest match per the no-auto-serial-match rule), picks the correct serial, pushes the corrected serial back. The manager copies, prints, sticks the new label, then rescans (validated against the issued serial; mismatches captured for audit).
  • Owner. Swap Support Officer triages; Inventory Support Officer resolves.
  • Escalation. Mandatory: Swap Support → Inventory.
  • Edge cases. Manager’s rescan after relabel does not match — captured separately; manager can re-request via thread.
  • Acceptance criteria.
    1. Escalation moves the case to the Inventory Support queue; Swap Support officer retains read access.
    2. Inventory’s “Issue corrected serial” action pushes the serial to the manager + opens the print/stick UI in Rechaj Swap.
    3. Subsequent rescan compares to __issuedSerial; mismatch shows the manager a specific error and writes an audit entry.
  • Trigger. Manager has an issue that doesn’t match any of 1.1–3.4.
  • Report-side flow. Support page → Something else… opens sheet-support → manager picks an issue-category chip (Equipment fault · Rider dispute · Station / facility · Cash handling · App / connectivity · Safety / incident · Other → free text + voice note), describes what happened, optionally attaches a photo and a voice note, submits.
  • Required fields. Category chip; free-text description; everything else optional.
  • Resolve-side flow (Atlas). Lands in a separate triage queue [Derived — tentative screen screen-triage-queue] visible to a “Triage” lane shared by Swap Support and Engineering Support. Triage officer can:
    • Re-route to a typed queue if the issue maps to an existing type (1.1–3.4).
    • Resolve in-thread for ad-hoc one-offs.
    • Promote: a recurring pattern (≥N reports in M days) becomes a candidate for formalization. [Derived — confirm threshold in Q5.]
  • Owner. Triage lane (Swap Support + Engineering Support shared) [Derived].
  • Escalation. Re-routing replaces escalation.
  • Edge cases. Safety / incident category should route directly into a priority lane (or trigger a paging integration). [Derived — see Q6.]
  • Acceptance criteria.
    1. “Other” cases produce no type-specific resolution actions — only generic resolve / re-route / message.
    2. Atlas exposes a per-category count over the last 30 days to support promotion-to-formal-type reviews.

  • Behaviour. When a manager submits any issue that blocks the active swap, the swap auto-parks; the manager’s queue moves on to the next rider. Manager can also park manually before submitting an issue.
  • Multiple parked swaps. A manager can hold multiple parked swaps simultaneously. Busy stations routinely have several stuck riders on different issues at once. (User flagged this as [Derived] in the brief; confirming as the default — see Q7.)
  • Parked queue surface. Dedicated section on the manager’s home screen lists every parked swap with rider name, plate, issue type, elapsed time, current status (Awaiting support / Needs your reupload / Resolved · tap to resume).
  • Resume path. Tapping a parked entry returns the manager to the exact swap-app step they parked from, with the resolution applied (if resolved) or the latest thread message visible (if awaiting).
  • Notifications. Push on resolution; push on new thread message that requires manager action (retake); soft in-app banner for thread messages that don’t require action.
  • Acceptance criteria.
    1. Parking does not lose any captured context; resume re-renders the same screen with the same data.
    2. Concurrent parked swaps render in a stable order (oldest first), with a count badge on the home tab.
    3. Resolution push deep-links to the parked swap, not the home screen.
    4. Two simultaneous parked swaps with different issue types can both resume independently without state collision.
  • Surface. Rechaj Swap: full-page sheet (sheet-support-thread, sheet-fullpage variant). Atlas: .thread-mini block inside the issue resolution screen.
  • Capabilities. Officer and manager exchange text messages; manager can attach photos / voice notes; officer can attach text only (no officer-side uploads in this release — confirm in Q8). [Derived]
  • Retake loop (first-class). Officer’s send-back-for-clearer-photo action writes a message AND simulates a structured retake request. Manager’s reupload appends a new version chip on the Atlas evidence preview AND a new thread message with the photo attached. This is the canonical retake mechanism; ad-hoc “please send a clearer one” text-only messages are allowed but bypass the version-chip workflow.
  • Photo viewing. Previously uploaded photos in the thread are tappable in Rechaj Swap; they open in a lightbox so the manager can compare against what they’re about to retake.
  • Persistence. Messages and attachments are immutable. Edits are appended messages, not edits-in-place.
  • Acceptance criteria.
    1. Both sides see the same messages in the same order in real time (≤2s lag).
    2. Send-back from Atlas appends the officer message immediately; the manager push fires within 10s.
    3. Manager’s reupload writes one message with the photo attached AND one version chip on the evidence preview.
    4. Thread persists indefinitely after case resolution; both sides can re-read.
  • Principle. Every resolution action takes only the case payload as input. Officers do not type identifiers that were captured at report time — no rider IDs, no wallet IDs, no battery serials, no transaction references, no station codes. Free-text fields are limited to (a) judgement notes (recorded for audit), (b) values that genuinely could not be captured automatically (e.g. the transaction reference / session ID from a photo).
  • Enforcement. Server-side: every resolution endpoint accepts a case_id and reads identifiers from the case record. Mismatched identifiers in the request body are rejected. UI-side: identifiers are non-editable display elements; the only inputs are decision dropdowns, notes, and the genuinely-uncaptured fields above.
  • Wrong-rider hard rule. Wallet credit endpoints (overdraft, manual top-up, refund) reject any request where the rider ID in the request does not match the rider ID on the linked case. This is mirrored by the overdraft-eligibility checkbox in the UI.
  • Acceptance criteria.
    1. No resolution form in Atlas has a free-text input for rider ID, wallet ID, battery serial, station code, or any identifier present in the case payload.
    2. Server-side endpoint smoke tests confirm rejection of mismatched identifiers.
    3. The audit entry records case_id and the loaded identifiers used in the resolution.
  • Trigger. Swap-complete screen in Rechaj Swap, after every swap (whether or not an issue occurred).
  • Surface. Compact module on screen-swap-complete: star rating (1–5), optional free-text, optional voice note, optional photo, Submit chip inline with the attach affordances. Renders above the CTAs (Start another swap · Back to dashboard) so all are in the viewport.
  • Resolve-side surface (Atlas). screen-manager-feedback, reachable from the sidebar entry “Manager feedback” and from a “View all feedback →” link on the support dashboard snippet. KPI tiles (today’s average, 5-star share, ≤2-star share, attachment count), filter pills (per rating, with photo, with voice), and a full table of submissions.
  • No officer action by default. Feedback is read-only. [Derived] Future: low-rated feedback with an attachment could auto-create a Triage case — confirm in Q9.
  • Acceptance criteria.
    1. Submit requires at least a rating (1–5 stars); other fields optional.
    2. Atlas feedback feed updates within 30s of submission.
    3. PM dashboard surfaces today’s averages and trends; per-station drill-down available.
  • Model. Officer types are records in a BusinessUnit × OfficerRole matrix. Issue types are tagged with a list of officer-type owners (typically one primary + zero or more escalation targets).
  • Scoping. Each officer’s Atlas queue is filtered to issue types they own (primary or escalated-to). A multi-role user sees a merged queue with per-row officer-type tags.
  • Escalation = routing handoff. Escalating an issue switches the owning_officer_type from the originating type to the target type. The originating officer retains read access but cannot resolve. Receiving officer’s queue gains the case immediately.
  • Atlas surface. [Derived] Sidebar nav lists scoped queues per officer-type the user holds. A user with Swap Support + Payment roles sees “Swap Support · 14”, “Payment · 3” as separate nav entries plus a merged “All open · 17” entry. Confirm in Q10.
  • Acceptance criteria.
    1. RBAC enforced at the action layer; UI hides actions the user cannot take.
    2. Escalation writes an audit entry capturing both officer types and the originating officer’s ID.
    3. Adding a future officer type (e.g. Energy) requires only a config row + queue route; no code changes for unrelated officer types.

Ground entities in existing prototype state where possible (scenarioMode, RIDER_BY_MODE, CASE_META, case state machines already drafted in swap-support/cases-and-backend.md). New / extended entities:

Entity Purpose Notable fields
Issue The case record itself. One per support report. id, type (1.1–3.4 + ‘other’), category (‘station’ / ‘wallet’ / ‘battery’ / ‘other’), status (open / in-progress / pending-evidence / escalated / resolved / denied), owning_officer_type, originating_officer_type (nullable, for escalations), reporter_id (manager), created_at, resolved_at, parked_swap_id (nullable).
IssueType Catalogue of the 11+1 types. id, category, primary_owner_officer_type, escalation_targets[], requires_photo_evidence (bool), report_sheet_id, resolve_screen_id.
IssuePayload The pre-captured context for an issue. Read at resolution time; never overwritten. issue_id, rider_id, wallet_id, battery_serial, station_id, manager_id, transaction_reference (nullable), originating_bank, destination_va, scanned_serial, free context_json.
IssueMessage One message in the per-issue thread. id, issue_id, from_side (‘manager’ / ‘officer’), from_user_id, body, created_at.
IssueAttachment Photo / voice attached to a message OR to the initial submission. id, issue_id, message_id (nullable), kind (‘photo’ / ‘voice’), version (int, monotonic per kind per issue), storage_uri, created_at.
EvidenceVersion [Derived] Computed view of attachments grouped by kind=photo; powers the Atlas version-chips strip. Materialized or query-time.
ParkedSwap A swap that’s been set aside. id, manager_id, rider_id, plate, parked_at_step (current Rechaj Swap screen ID + state), linked_issue_id (nullable for manual parks), current_status, last_thread_message_at.
OfficerRole A role assignment on a user. user_id, officer_type, business_unit_id, active.
OfficerType A typed role (Swap Support / Payment / Engineering / Inventory / Facility / Energy). id, name, business_unit_id, scope_default (queue filter).
BusinessUnit Top-level org division. id, name, active.
ResolutionAction A typed action an officer can take. Concrete actions: issue-overdraft, lift-overdraft-ban, reassign-battery, claim-battery, assign-battery, update-primary-station, approve-temp-swap, deny-temp-swap, issue-corrected-serial, escalate-to-engineering, escalate-to-inventory, request-clarification, resolve-other. id, issue_type[], requires_officer_type[], idempotent_on[].
AuditLog Append-only record of every action. id, actor_user_id, actor_officer_type, action_type, target_id, case_id, before_state, after_state, delta, timestamp, note.
SwapFeedback One per completed swap. id, swap_id, manager_id, rating (1–5), note, voice_uri, photo_uri, created_at.
  • Issue 1–1 IssuePayload · 1–N IssueMessage · 1–N IssueAttachment · 0–1 ParkedSwap.
  • IssueType defines primary_owner_officer_type (one) and escalation_targets[] (zero or more).
  • OfficerRole is many-to-many between User and OfficerType; a user with multiple OfficerRole rows sees the union of queues.
  • ResolutionAction is gated by requires_officer_type[]; rejecting a call where the actor’s officer type is not in the list is a server-side hard check.
  • open → in-progress on first officer view.
  • in-progress → pending-evidence on request-clarification (officer sends back).
  • pending-evidence → in-progress on manager reupload.
  • in-progress → escalated on escalate-to-* action; owning_officer_type changes.
  • in-progress → resolved / denied on resolution action.
  • escalated → in-progress (in the receiving queue) on first view by the receiving officer.
  • No technical case codes are user-facing for swap managers. Internal IDs (case ID, request ID) exist for back-end / officer reference; manager-facing surfaces hide them per the no-tech-codes rule.
  • Money-moving endpoints are idempotent on (case_id, action_type, request_key) per the existing backend spec.
  • Audit entries are immutable. Corrections are new entries that reference the original by correction_of.

Per-issue-type and per-feature acceptance criteria are listed inline in §6 and §7. Top-level acceptance for the release:

  1. No resolution form in Atlas requires the officer to type an identifier that was captured at report time. Verified by code grep on resolution screens + endpoint contract tests.
  2. The 17 May wrong-rider incident class is reproducibly blocked: integration test issues an overdraft against case A’s payload using case B’s rider ID in the request body → server returns 400.
  3. All 11 issue types + Other have a working end-to-end report → resolve flow in staging, exercised by manual test plan + automated smoke.
  4. A manager can park ≥3 swaps concurrently and resume each independently.
  5. Send-back-for-clearer-photo round-trips end-to-end on 2.1, 3.1, 3.3 (and 3.2, 3.4 where photo is required) in ≤30s wall-clock on staging.
  6. Every resolution action writes an immutable audit entry with the full payload.
  7. RBAC: a user assigned only Swap Support cannot view or take action on a 2.4 escalated to Engineering.
  8. Feedback submissions land in the Atlas Manager feedback module within 30s and aggregate into the support dashboard snippet.

Metric Target Source
% of support traffic in-app vs WhatsApp ≥95% within 1 month of GA Support team weekly review
Median time-to-acknowledge < 2 min (in-swap-blocking issues) AuditLog first-view event
Median time-to-resolve < 10 min (3.1, 3.2, 2.1); < 24h (1.2) AuditLog resolve event minus Issue.created_at
Wrong-rider-class incidents 0 Incident log; expected 0 by design
Manager throughput under park ≥3 subsequent swaps completed per parked swap before resume ParkedSwap + swap completion events
Re-request rate per issue type Track; expect 2.1 highest (receipt clarity), declining over time IssueMessage with kind=clarification
Issue-type distribution Track; expect battery group ≈ 50% in week 1, declining as inventory-cause backlog clears Issue.type aggregations
Feedback rating average Track; expect ≥4.0; sub-station drill-down for outliers SwapFeedback.rating

Instrument all events via the audit log + a thin metrics layer; no separate analytics pipeline for this release. [Derived]


  1. SLA targets. Are the [Derived] medians above (2 min ack / 10 min resolve) the right anchors, or should we anchor to p95 / p99? — Ops + Eng.
  2. Payment Officer scope. Which 2.x issues, if any, route to Payment Officer directly vs flow through Swap Support first? Or is Payment Officer purely an escalation target for 2.4 / 2.5 alongside Engineering Support? — Finance + Ops.
  3. Temp-swap auto-deny on outstanding overdraft. Should 1.1 be blocked at submit if the rider has an unresolved 2.2? Or surface as a warning to the officer? — Ops.
  4. Primary-station-change cooldown. Should the same rider be prevented from requesting 1.2 more than once / 30 days? — Ops + Finance (wallet-arbitrage prevention).
  5. “Other” promotion threshold. What recurrence count (N reports in M days) triggers a candidate-for-formalization review? — PM.
  6. Safety / incident routing. Should “Other → Safety / incident” trigger a paging integration immediately, or sit in the Triage queue? — Ops + Eng.
  7. Multiple parallel parked swaps. Confirming as the default per the brief’s [Derived] flag — any cap on concurrent parked swaps per manager? — Ops.
  8. Officer-side uploads in the thread. Should officers be able to attach references / screenshots in the thread, or text-only? — Support team.
  9. Auto-Triage on low feedback. Should rating ≤2 with an attached photo / voice auto-create a Triage case? — PM + Ops.
  10. Multi-role queue layout in Atlas. Per-officer-type sub-queues + merged “All open” — confirm vs single-merged queue with type filter. — Support team.
  11. Retiring older Atlas screens. screen-issue-mgr-transfer (station-wallet payment failed, was scenario 7) and screen-issue-deduction-fail (daily-fee deduction failed, was scenario 5) are not in the new 11-type taxonomy. Retire fully, or keep as engineering-debug-only surfaces? — Eng.
  12. Phantom-fee + Acct-invalid Atlas screens. Tentative IDs screen-issue-phantom-fee and screen-issue-acct-invalid are [Derived] — confirm naming.
  13. Feedback data retention. How long do we keep voice notes? — Legal + Ops.