Token Approval System
Students consume two kinds of "currency" in the student app — AI Coins (used for AI tutor questions, ~2 coins per query) and Teacher Credits (used to ask a human teacher a doubt). When they run out, they request a top-up. Admins review the queue, then Authorize or Decline. The student's wallet updates on approval; on decline they get the rejection reason.
At a glance
| Who can do this | Students request · Admins & sub-admins with token permission authorize/decline |
| Where it lives | Student app → /req-coin and /req-credits · Admin panel → /dashboard/school/:id/req-coin (and an inline tab on the student detail page) |
| Triggers notifications? | Yes — on approve and on decline |
| Related features | Coins & Credits · AI Tutor · Doubts |
How it flows
Status lifecycle
A request stays in pending until an admin acts. There's no automatic timeout.
The student side
/req-coin — request AI Coins
Top of the page is an "AI Access" info card explaining "1 AI query ≈ 2 coins". Below:
- Quick presets:
+100,+250,+500— tapping one fills the amount field. Default selected preset is 250. - Enter coins — manual numeric input with
+/-steppers. - Purpose — required free-text. Empty purpose blocks submission with a toast.
- Submit button: "Send Request". On success, navigates back to
/dashboard.
Validation:
- Amount must be > 0.
- Purpose must be non-empty after trim.
/req-credits — request Teacher Credits
Same shape as /req-coin but for teacher credit, used for asking human teachers questions. Request type teacher_credit.
The student does not see a separate "my requests" page on the admin side. Instead, their pending/approved/rejected history is implicit (a successful approval simply tops up their wallet; a rejection appears as a notification with the reason).
The admin side
Main queue: /dashboard/school/:id/req-coin
Titled Asset Allocation Registry in the UI ("Authorize/Decline" language is used throughout — that's the same as approve/reject).
Columns:
| Column | What it shows |
|---|---|
| Initiator | Student name + ID |
| Resource Type | AI Coins (gold tag) or Teacher Credit (green tag) |
| Volume | The requested amount, large numeric |
| Progress | Status: Reviewing (gold), Authorized (green), Declined (red) |
| Timeline | Created at — date + time |
| Actions | AUTHORIZE / DECLINE for pending; eye icon for already-actioned |
Filters in the toolbar:
- Search by student identity (debounced 500ms).
- Date range with a "Filter Ledger" button to apply, plus a Reset button.
- Resource Type filter: AI Coins / Teacher Credit / all.
- Status filter: pending / approved / rejected / cancelled / all.
Rows are clickable — opens the detail modal ("Asset Request Intelligence") showing:
- Student card with status tag
- Asset Class card (AI Coins vs Teacher Credit)
- Allocation Volume card (the amount)
- "Operational Rationale" (the purpose /
estimatedUsagefield the student typed) - Transaction Pipeline (created-at timestamp; if reviewed, who reviewed it)
- For pending requests, a footer "Authorize Units" button as a second affordance.
The student-detail tab
When admins drill into a single student (/dashboard/school/:id/students/:studentId), the Token Requests tab shows the same list scoped to that student, with a small badge counting pending requests. The Approve / Reject buttons there work identically to the main queue, and the Reject path uses an inline Popconfirm rather than a centered modal.
Authorize action
- Single click on
AUTHORIZE. No confirm dialog. - Toast on success: "Request authorized successfully".
- Status flips to
approved, the row shows the green tag, and actions collapse to a view-only eye icon.
Decline action
- Click
DECLINE→ confirm modal: "Are you sure you want to decline this asset request?" - On confirm, the request is rejected with a fixed admin-side reason: "Transaction declined by administration". (There is no free-text reason input in the current admin UI; the student just sees that string.)
- Toast: "Request declined".
Partial approval
The current admin UI does not support partial approvals. The only shipped actions are Authorize (grants the full requested amount) and Decline (grants nothing). A "partial approve" would have to come as a future enhancement.
What the student sees back
- Approved: wallet balance increases by the requested amount; push + in-app notification fires (see Notifications).
- Rejected: notification with the admin's reason text. The student's wallet is untouched.
- Cancelled: status reserved for student-initiated withdrawal of a pending request. The list filter exposes it but no admin action produces this status.
Edge cases & things to test
- Double-click AUTHORIZE — the button should be disabled / loading after the first click. Verify a request can't be approved twice.
- Decline then re-request — student declines a request, immediately requests the same amount again. Should produce a second
pendingrow, not edit the first. - Missing purpose on the student form — submission should fail client-side with a toast. Confirm.
- Amount of 0 or negative — submission should fail client-side. Confirm.
- Filter combinations — type=AI Coins + status=pending + date range last 7 days; verify pagination resets to page 1 when any filter changes.
- Student detail tab badge — when a request is approved, the pending badge count decreases. Refresh the tab and confirm the badge is in sync with the row statuses.
- Click the row vs click the action button — clicking a button shouldn't also open the detail modal (event propagation must be stopped).
- Approved request seen on student detail —
actionscell should render—(em-dash), not buttons. - Sub-admin without permission — should not see the
/req-coinlink in the school sidebar at all. - Notification fan-out — verify the student's parent (if any) is notified when the request is approved/declined, depending on the school's notification setting.
- Wallet sync — approve while the student has the wallet screen open in the student app; the new balance should appear without requiring a manual refresh (Socket.IO update).
- Search by student ID vs name — the placeholder says "Find requests by student identity"; verify search matches both.
Related
- Coins & Credits — the two currencies and where they're spent
- AI Tutor — what AI Coins are spent on
- Doubts — what Teacher Credits are spent on
- Student Details — the per-student token requests tab
- Notifications — what the student gets back