Skip to main content

Overview

The Admin Dashboard provides comprehensive tools for platform administrators to manage users, trips, bookings, financial operations, and generate reports. Admins have elevated permissions to oversee all platform activities and intervene when necessary.

Admin Authentication

All admin endpoints require the AdminPolicy authorization:
src/services/Trips/Trips.Api/Features/AdminTripManagement/AdminTripManagementEndpoints.cs
RouteGroupBuilder group = app.MapGroup("/api/admin/trips")
    .RequireAuthorization("AdminPolicy")
    .WithTags("Admin Trip Management")
    .WithOpenApi();
Admin operations are logged and audited. All actions require valid admin credentials and proper authorization.

Trip Management

View All Trip Requests

Admins can view booking requests for any trip:
GET /api/admin/trips/{tripId}/requests?status=Pending
Query Parameters:
  • status (optional): Filter by booking status (Pending, Confirmed, Rejected, Cancelled)
Response:
{
  "success": true,
  "tripId": "t_abc123",
  "requests": [
    {
      "bookingId": "b_xyz789",
      "passengerId": "p_123456",
      "passengerName": "Mohammed Ahmed",
      "requestedSeats": 2,
      "totalPrice": 500.00,
      "currency": "SAR",
      "paymentMethod": "Wallet",
      "status": "Pending",
      "requestedAt": "2026-03-10T12:00:00Z"
    }
  ]
}

Accept Booking Request

POST /api/admin/trips/{tripId}/requests/{bookingId}/accept
{
  "notes": "Approved by admin on driver's behalf"
}
src/services/Trips/Trips.Api/Features/AdminTripManagement/AdminTripManagementEndpoints.cs
group.MapPost("/{tripId}/requests/{bookingId}/accept", async (
    string tripId,
    string bookingId,
    [FromBody] AdminAcceptRequestRequest request,
    [FromServices] IMediator mediator,
    ClaimsPrincipal user,
    CancellationToken cancellationToken) =>
{
    string? adminId = user.GetUserId();
    if (string.IsNullOrEmpty(adminId))
        return Results.Unauthorized();

    var command = new AdminAcceptRequestCommand(
        tripId, bookingId, adminId, request.Notes);

    AdminAcceptRequestResponse response = await mediator.Send(command, cancellationToken);
    return response.Success ? Results.Ok(response) : Results.BadRequest(response);
})

Reject Booking Request

POST /api/admin/trips/{tripId}/requests/{bookingId}/reject
{
  "reason": "Passenger has outstanding payment issues"
}

Add Passenger Directly

Admins can add passengers to trips without requiring approval:
POST /api/admin/trips/{tripId}/passengers
{
  "passengerId": "p_123456",
  "requestedSeatsCount": 1,
  "paymentMethod": "Cash",
  "notes": "Special booking from customer service"
}

Remove Passenger from Trip

DELETE /api/admin/trips/{tripId}/passengers/{passengerId}?reason=Duplicate+booking

Cancel Trip

POST /api/admin/trips/{tripId}/cancel
{
  "reason": "Driver unavailable due to emergency"
}

View Cancelled Trips

GET /api/admin/trips/cancellations
Query Parameters:
  • driverId - Filter by driver
  • from - Filter by departure location
  • to - Filter by destination
  • cancelledFrom - Start date of cancellation period
  • cancelledTo - End date of cancellation period
  • departureFrom - Start date of original departure
  • departureTo - End date of original departure
  • page - Page number (default: 1)
  • pageSize - Items per page (default: 50)
Response:
{
  "success": true,
  "trips": [
    {
      "tripId": "t_abc123",
      "driverId": "d_789012",
      "driverName": "Ahmed Ali",
      "from": "Riyadh",
      "to": "Jeddah",
      "departureTime": "2026-03-15T08:00:00Z",
      "cancelledAt": "2026-03-14T10:30:00Z",
      "cancelReason": "Vehicle breakdown",
      "confirmedBookings": 3,
      "totalPassengers": 5
    }
  ],
  "totalCount": 15,
  "page": 1,
  "pageSize": 50
}

Trip Replacement

When a trip is cancelled, admins can replace it with a new driver or existing trip:

Replace with New Driver

POST /api/admin/trips/{tripId}/replace-with-driver
{
  "newDriverId": "d_456789",
  "vehicleId": "v_012345",
  "transferAllBookings": true,
  "notes": "Replacement driver assigned due to original driver emergency"
}
1

Validate Replacement Driver

Ensures the new driver is available for the trip time slot.
2

Create New Trip

Creates a new trip with the same route and details.
3

Transfer Bookings

Moves all confirmed bookings from cancelled trip to new trip.
4

Notify Users

Sends notifications to all affected passengers and the new driver.

Replace with Existing Trip

POST /api/admin/trips/{tripId}/replace-with-trip
{
  "replacementTripId": "t_def456",
  "transferAllBookings": true,
  "notes": "Merged with existing trip on same route"
}

Get Replacement Options

Find suitable replacement trips or drivers:
GET /api/admin/trips/{tripId}/replacement-options
Response:
{
  "success": true,
  "matchingTrips": [
    {
      "tripId": "t_def456",
      "driverId": "d_456789",
      "driverName": "Khalid Mohammed",
      "from": "Riyadh",
      "to": "Jeddah",
      "departureTime": "2026-03-15T09:00:00Z",
      "availableSeats": 3,
      "price": 250.00
    }
  ],
  "availableDrivers": [
    {
      "driverId": "d_789456",
      "name": "Omar Hassan",
      "rating": 4.8,
      "vehicles": [
        {
          "vehicleId": "v_123789",
          "type": "Sedan",
          "seatCount": 4
        }
      ]
    }
  ]
}

Get Available Drivers

Search for drivers available to take over a trip:
GET /api/admin/trips/{tripId}/available-drivers?searchNameOrPhone=Ahmed

Financial Dashboard

View Revenue Statistics

GET /api/admin/statistics/revenue
src/services/Trips/Trips.Api/Features/AdminStatistics/GetRevenue/GetRevenueEndpoint.cs
app.MapGet("/api/admin/statistics/revenue", async (
    [FromServices] IMediator mediator,
    CancellationToken cancellationToken) =>
{
    var query = new GetRevenueQuery();
    GetRevenueResponse result = await mediator.Send(query, cancellationToken);
    return result.Success ? Results.Ok(result) : Results.BadRequest(result);
})
Response:
{
  "success": true,
  "totalRevenue": 125000.00,
  "currency": "SAR",
  "totalTrips": 450,
  "completedTrips": 420,
  "totalCommission": 12500.00,
  "period": "all-time"
}

View Trip Movement Statistics

GET /api/admin/statistics/trips-movement?period=today
Available Periods:
  • today - Statistics for current day
  • week - Statistics for current week
  • month - Statistics for current month
src/services/Trips/Trips.Api/Features/AdminStatistics/GetTripsMovement/GetTripsMovementEndpoint.cs
app.MapGet("/api/admin/statistics/trips-movement", async (
    [FromServices] IMediator mediator,
    [FromQuery] string period = "today",
    CancellationToken cancellationToken = default) =>
{
    var query = new GetTripsMovementQuery { Period = period };
    GetTripsMovementResponse result = await mediator.Send(query, cancellationToken);
    return result.Success ? Results.Ok(result) : Results.BadRequest(result);
})
Response:
{
  "success": true,
  "period": "today",
  "scheduled": 25,
  "inProgress": 8,
  "completed": 12,
  "cancelled": 2,
  "totalBookings": 68,
  "confirmedBookings": 45,
  "pendingBookings": 15,
  "rejectedBookings": 8
}

Wallet Management

Withdraw from Driver Wallet

Process driver withdrawal requests:
POST /api/admin/drivers/{driverId}/wallet/withdraw
{
  "amount": 1000.00,
  "currency": "SAR",
  "transferReference": "IBAN: SA1234567890, Transfer ID: TRX123456",
  "notes": "Weekly withdrawal request processed"
}
Implementation:
src/services/Trips/Trips.Api/Features/Admin/DriverWallets/WithdrawFromDriverWallet.cs
public sealed class WithdrawFromDriverWalletHandler(
    IWalletOperationService walletOps,
    IUsersApiService usersApiService,
    ILogger<WithdrawFromDriverWalletHandler> logger,
    IMessageBus messageBus)
    : IRequestHandler<WithdrawFromDriverWalletCommand, WithdrawFromDriverWalletResponse>
{
    public async Task<WithdrawFromDriverWalletResponse> Handle(
        WithdrawFromDriverWalletCommand request, 
        CancellationToken cancellationToken)
    {
        string currencyCode = await CurrencyResolver.ResolveCodeAsync(
            request.Currency, usersApiService, cancellationToken);

        var result = await walletOps.AdminWithdrawFromDriverAsync(
            new AdminWithdrawFromDriverRequest(
                request.DriverId,
                currencyCode,
                request.Amount,
                request.AdminId,
                request.TransferReference,
                request.Notes),
            cancellationToken);

        await (result.Success
            ? messageBus.PublishAsync(new WalletWithdrawnNotification(
                request.DriverId,
                request.Amount,
                currencyCode,
                result.BalanceAfter,
                request.TransferReference))
            : ValueTask.CompletedTask);

        return new WithdrawFromDriverWalletResponse
        {
            Success = result.Success,
            Message = result.Success
                ? $"تم سحب {request.Amount} {currencyCode} بنجاح"
                : result.ErrorMessage ?? "فشل في سحب المبلغ",
            NewBalance = result.BalanceAfter
        };
    }
}

Approve Wallet Top-Up

Review and approve passenger wallet top-up requests:
POST /api/wallet/top-up/bank-transfer/{transferId}/approve
{
  "verifiedAmount": 500.00
}

Reject Wallet Top-Up

POST /api/wallet/top-up/bank-transfer/{transferId}/reject
{
  "reason": "Receipt image is unclear. Please resubmit with a clearer image."
}

Bank Transfer Management

Admins review and process all bank transfer requests:

View Pending Transfers

GET /api/admin/bank-transfers?status=Pending&type=WalletTopUp
Transfer Types:
  • WalletTopUp - Wallet recharge requests
  • Booking - Trip booking payments

User Management

List Admins

GET /api/admin/admins?page=1&pageSize=20

Create Admin

POST /api/admin/admins

Update Admin

PUT /api/admin/admins/{adminId}

Delete Admin

DELETE /api/admin/admins/{adminId}

Review Management

View All Driver Reviews

GET /api/admin/driver-reviews?page=1&pageSize=50

Delete Inappropriate Review

DELETE /api/driver-reviews/{reviewId}
DELETE /api/passenger-reviews/{reviewId}
Deleting a review automatically recalculates the overall rating for the affected user.

Company Management

List All Companies

GET /api/admin/companies?page=1&pageSize=20&searchName=Transport

View Company Details

GET /api/admin/companies/{companyId}

Update Company

PUT /api/admin/companies/{companyId}

Withdraw from Company Wallet

POST /api/admin/companies/{companyId}/wallet/withdraw

Currency Management

List Currencies

GET /api/admin/currencies

Create Currency

POST /api/admin/currencies

Update Currency

PUT /api/admin/currencies/{currencyId}

Commission Policies

List Commission Policies

GET /api/admin/commission-policies

Create Commission Policy

POST /api/admin/commission-policies

Update Commission Policy

PUT /api/admin/commission-policies/{policyId}

Audit & Logging

All admin actions are logged for audit purposes:
logger.LogInformation(
    "Admin {AdminId} cancelled trip {TripId} with reason: {Reason}",
    adminId, tripId, reason);
Admin logs are immutable and stored for compliance purposes. All actions are traceable.

Dashboard Metrics

Active Users

Total active drivers, passengers, and companies

Revenue

Total platform revenue and commission earnings

Trip Volume

Scheduled, in-progress, and completed trips

Pending Actions

Bank transfers, reviews, and bookings requiring attention

Best Practices

Review Regularly

Check pending transfers and bookings daily to ensure smooth operations.

Document Actions

Always add notes when performing manual interventions.

Monitor Metrics

Track key performance indicators to identify trends and issues.

Handle Disputes

Mediate between drivers and passengers fairly and promptly.

Build docs developers (and LLMs) love