Skip to content

Tips history

Purpose

The Tips screen has two faces:

  1. Player → player tips — peer-to-peer in-chat micro-transfers. The admin view here is read-only audit (/admin/tips).
  2. Admin → player tips — operator-funded grants (refunds, goodwill). These are SuperAdmin-only and require OTP. They show up under the same /tips UI but live behind separate endpoints.

Both share an audit log and both pass through Transaction rows for accounting.

Audience

Customer support (admin tips for compensation), risk (P2P abuse review), finance (admin-tip pool reconciliation).

Path in admin-fe

Screen URL Page
Tips list /tips ebit-admin-fe/src/app/(dashboard)/tips/page.tsx
Tip detail /tips/[id] ebit-admin-fe/src/app/(dashboard)/tips/[id]/page.tsx

The "Tip user" / "Deduct balance" buttons live in user-profile.md (drawer action, not on the Tips list itself).

Backing API endpoints

Endpoint Source
GET /admin/tips (P2P tips audit) apps/api/src/tips/admin.tips.controller.ts:15
GET /admin/admin-tips (admin-funded tips list) apps/api/src/admin-tips/admin.admin-tips.controller.ts:48
POST /admin/admin-tips (tip a user, SuperAdmin) apps/api/src/admin-tips/admin.admin-tips.controller.ts:28
POST /admin/admin-tips/deduct-balance (negative tip, SuperAdmin) apps/api/src/admin-tips/admin.admin-tips.controller.ts:38

Frontend wiring: ebit-admin-fe/src/queries/tips/.

Key actions

Action Required permission / role API call DB tables touched Audit-logged?
List P2P tips tip.view GET /admin/tips Tip, User yes
List admin tips admin-tips.view GET /admin/admin-tips AdminTip, User yes
Tip a user (admin-funded) admin-tips.tip POST /admin/admin-tips AdminTip, Account, Transaction yes
Deduct from a user (admin-funded) admin-tips.deduct-balance POST /admin/admin-tips/deduct-balance AdminTip (negative), Account, Transaction yes

Filters and views

  • Type — P2P (player→player) or Admin (operator→player).
  • From / To — userId of the sender or receiver.
  • Date range.
  • Amount range (USD-equiv).
  • Reason — free text on admin tips; filterable as substring match.

Common workflows

  1. Compensate a player after a known incident. From user-profile.md, click "Tip user". Modal opens. Fill amount + reason ("post-incident credit per ticket #1234"). OTP. Backend writes AdminTip, increments player balance, writes Transaction. Cross-link the Zendesk ticket via the reason field.
  2. Reverse an erroneous tip / deposit. Compliance discovers a stuck deposit was credited twice. They use POST /admin/admin-tips/deduct-balance with negative amount (semantically a deduct). Player's balance decreases. Both rows visible on this screen with Transaction chain.
  3. Investigate suspicious P2P pattern. Risk filters the Tips list by sender/receiver, looks for circular flows (bonus-arbitrage). Cross-references with bets-history.md and withdrawals.md.
  4. Monthly admin-tip pool reconciliation. Finance filters admin tips by date range, sums by currency, cross-checks against the configured Vault source for the admin-tip pool. Discrepancy → escalate.
  5. Player asks "who sent me this tip"? Open /tips/[id], see sender User reference. P2P tips show sender + receiver; admin tips show admin operator + receiver.

Edge cases / gotchas

  • P2P tips have a chat-rate-limit. Spam-detection is on the chat side, not here. Anomalies on this screen often mean the chat limiter failed.
  • Admin tips bypass deposit limits. Granting via admin-tips lets you exceed a player's gambling-limit-style caps; finance must approve. SuperAdmin-only enforcement is the safety net.
  • deduct-balance can drive a balance negative. Backend allows it (operations sometimes need to). The player can't bet from a negative balance, but they can deposit to recover.
  • Reason text is stored verbatim. Don't put PII or external IDs that could leak — admin logs are reviewed by ops, not all admins.
  • Tip transactions are NOT undoable. There is no "cancel admin tip" button. To reverse, issue an opposing admin tip or deduct.
  • Batch tips are not supported. Each POST /admin/admin-tips is one user. For broad makegoods (thousands of users), engineering runs a script.

Sequence — admin-funded tip

sequenceDiagram
    actor sa as SuperAdmin
    participant admin-fe
    participant api
    participant pg as Postgres
    sa->>admin-fe: open /users/[id], click "Tip user", amount=50 USD, reason="..."
    admin-fe->>api: POST /admin/admin-tips { userId, amount, currency, reason }, x-otp
    api->>api: PermissionGuard('admin-tips.tip') + OtpGuard
    api->>pg: BEGIN
    api->>pg: INSERT Transaction (FROM admin-tip-pool TO user, type=ADMIN_TIP)
    api->>pg: UPDATE Account SET balance += amount WHERE userId
    api->>pg: INSERT AdminTip (adminUserId, userId, amount, reason)
    api->>pg: INSERT AdminActionLog
    api->>pg: COMMIT
    api-->>admin-fe: 200 OK with AdminTip DTO
    admin-fe-->>sa: confirmation toast