Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/Muhammadbugaje/trustride/llms.txt

Use this file to discover all available pages before exploring further.

Drivers are the supply side of TrustRide. They register vehicles, publish intercity trips, verify payments from riders via receipt chat, and manage the full booking lifecycle including refunds and ambassador approvals. All driver-facing endpoints require role=driver and, for trip publication, is_driver_verified=True.

Driver Registration and Verification

Drivers register at POST /users/register/ with role=driver. The registration process is identical to rider registration — the same fields (email, phone, first_name, last_name, gender, password) are required. After registration the driver account is inactive for trip publication until an admin sets is_driver_verified=True.
Unverified drivers (is_driver_verified=False) can log in and access the dashboard, but they cannot publish trips. The dashboard prominently displays a verification status banner. Attempting to create or publish a trip while unverified returns an error message and redirects the user.
The UserManager provides a verified_drivers() queryset shortcut:
# Returns all drivers who have been admin-verified
User.objects.verified_drivers()
# Equivalent to: User.objects.filter(role='driver', is_driver_verified=True)
Model validation also prevents is_driver_verified from being set on a non-driver account:
def clean(self):
    if self.is_driver_verified and not self.is_driver:
        raise ValidationError({
            'is_driver_verified': 'Only drivers can be verified as drivers.'
        })

Driver Dashboard

GET /driver/dashboard/ — requires login and role=driver. The driver dashboard aggregates everything a driver needs to manage their business:
  • Active trips — upcoming published trips with departure date ≥ today.
  • Pending bookings — count of bookings awaiting payment approval (reserved or pending_verification).
  • Earnings summary — total earnings from confirmed bookings (SUM(price) where status=confirmed).
  • Vehicle count — number of vehicles in the driver’s fleet.
  • Pending refunds — count of open refund requests on the driver’s trips.
  • Pending driver reports — count of unreviewed DriverReport records.
  • Ambassador requests — count of pending ambassador approval requests.
  • Average rating — computed from all Rating records where reviewee=driver.

Vehicle Management

A driver must add at least one vehicle before creating a trip. Vehicles are linked to trips and determine seat capacity.
1

Add a Vehicle

GET/POST /driver/vehicles/add/ — renders a vehicle form alongside an image formset (1–10 images, minimum 1 required).
2

Edit a Vehicle

GET/POST /driver/vehicles/<uuid>/edit/ — pre-fills the form with the existing vehicle’s data.
3

Delete a Vehicle

POST /driver/vehicles/<uuid>/delete/ — shows a confirmation page then deletes the record.

Vehicle Model Fields

class Vehicle(UUIDModel, TimeStampedModel):
    driver            = models.ForeignKey(User, limit_choices_to={'role': 'driver'})
    make              = models.CharField(max_length=50)
    model             = models.CharField(max_length=50)
    year              = models.IntegerField()          # 1900 – current year + 1
    color             = models.CharField(max_length=30)
    plate_number      = models.CharField(max_length=20, unique=True)  # e.g., ABC-123DE
    vehicle_type      = models.CharField(choices=['sedan', 'suv', 'minivan', 'bus', ...])
    seating_capacity  = models.IntegerField()
    passenger_capacity = models.IntegerField()         # must not exceed seating_capacity
    car_image         = models.ImageField(upload_to='vehicles/%Y/%m/')
    seat_layout       = models.JSONField(default=dict)
    is_active         = models.BooleanField(default=True)
The plate number is validated against the Nigerian plate format (ABC-123DE or ABCD-123DE) by validate_plate_number in apps/core/validators.py.

Seat Layout JSON Format

The seat_layout field is a JSON object that describes how seats are arranged in the vehicle. The total_seats property iterates over the layout to compute total capacity:
{
  "front": 2,
  "middle": [3, 3],
  "back": 3
}
In this example: 2 front seats + 6 middle seats (two rows of 3) + 3 back seats = 11 total seats. For the seat map rendered on the trip detail page, seats are additionally labelled row/column style (e.g., A1, A2, B1, …) based on seating_capacity.

Creating Trips

POST /create/ — drivers fill in the trip form. Required fields:
FieldDescription
vehicleUUID of one of the driver’s active vehicles
originDeparture city (free text, validated from Nigerian states list)
destinationArrival city
departure_dateMust be today or a future date for publishing
departure_time24-hour time
price_per_seatPrice in NGN (must be ≥ 0)
gender_restrictionanyone, ladies_only, or gentlemen_only
driver_noteOptional note shown to riders (e.g., “Arrive 10 minutes early”)
stop_countNumber of intermediate stops
stop_<n>_city, stop_<n>_arrival, stop_<n>_departure, stop_<n>_pricePer-stop data
Trips created via the form are published directly (status='published'). To create a trip in draft and publish later, use the duplicate-and-edit workflow. A trip in draft status is invisible to riders until POST /trip/<uuid>/publish/ is called.

Trip Status Lifecycle

draft → published → in_progress → completed

           cancelled
StatusDescription
draftNewly duplicated trips or trips awaiting edits. Not visible to riders.
publishedLive and bookable. Shown in search results.
in_progressTrip has started (driver called /start-trip/<uuid>/). No new bookings allowed.
completedTrip finished (driver called /complete-trip/<uuid>/). Riders can now rate.
cancelledCancelled by driver. Pending bookings are automatically cancelled.
expiredSet by admin or a background task for stale trips.

Trip Management

All trip management actions are accessible from the trip manage page at GET /trip/<uuid>/manage/.
ActionEndpointNotes
Edit tripPOST /trip/<uuid>/edit/Blocked if status is completed or cancelled.
Pause / resumePOST /trip/<uuid>/pause/Toggles is_active. Hides trip from search without cancelling bookings.
PublishPOST /trip/<uuid>/publish/Moves draftpublished. Departure date must not be in the past.
CancelPOST /trip/<uuid>/cancel/Sets status=cancelled and cancels all pending bookings. Notifies riders via chat.
StartPOST /start-trip/<uuid>/Moves publishedin_progress.
CompletePOST /complete-trip/<uuid>/Moves in_progresscompleted. Increments total_rides for driver and all confirmed riders. Purges waitlist and chat messages.
DuplicatePOST /trip/<uuid>/duplicate/Creates a new draft trip with the same settings. Departure date defaults to today; driver must update and publish.

Payment Verification

When a rider books a seat, an automated chat message is sent to the booking conversation with the driver’s bank account details and payment instructions. The rider transfers funds and uploads a receipt screenshot in the chat. The driver reviews the receipt and approves: POST /booking/<uuid>/approve/ — driver only. Transitions booking to confirmed, sets confirmed_at, sends the rider a QR-code confirmation email, and creates an in-app notification.
# Approval view (simplified)
booking.status = 'confirmed'
booking.confirmed_at = timezone.now()
booking.save()
send_booking_confirmation_email(booking)
Notification.objects.create(user=booking.rider, title='✅ Payment Approved!', ...)
Drivers can also cancel an unconfirmed booking directly from the manage page via POST /booking/<uuid>/cancel/. This releases the seat and notifies the rider. For already-confirmed bookings, use the refund flow instead.

Refund Management

Riders request refunds from their booking detail page. Drivers see all refund requests for their trips at GET /driver/refunds/, which shows counts for requested, approved, and rejected statuses.
ActionEndpointOutcome
Approve refundPOST /refund/<uuid>/approve/Sends approval email to rider, releases the seat, deletes the booking.
Reject refundPOST /refund/<uuid>/reject/Sends rejection email with reason. Booking remains confirmed.

Ambassador Requests

Drivers control which approved ambassadors can sell seats on their specific trips. The workflow has two views:
  • GET/POST /driver/ambassador-requests/ — shows pending AmbassadorTripApproval records (is_approved=False) and allows the driver to approve or reject each one.
  • GET/POST /driver/manage-ambassadors/ — shows all approved and paused ambassadors grouped by trip. Drivers can pause, resume, or permanently remove an ambassador from a trip.

Driver Reports

Riders can submit a DriverReport against any trip the driver runs. Drivers view their reports at GET /driver/reports/.
class DriverReport(UUIDModel, TimeStampedModel):
    reporter = models.ForeignKey(User, related_name='reports_submitted')
    driver   = models.ForeignKey(User, related_name='reports_received')
    trip     = models.ForeignKey(Trip, related_name='reports')
    reason   = models.CharField(choices=[
        'inappropriate_behavior', 'safety_concern',
        'trip_cancelled', 'vehicle_issue', 'other'
    ])
    details  = models.TextField()
    status   = models.CharField(choices=['pending', 'reviewed', 'resolved', 'dismissed'])
The driver/reports/ page shows pending_count and resolved_count alongside admin contact details so drivers can follow up.

Commission Rate and Payouts

The commission_rate field on User represents the platform’s percentage cut from a driver’s earnings. It is set per driver by admin and must be between 0 and 100.
commission_rate = models.DecimalField(max_digits=5, decimal_places=2, default=0.00)
Net payout is calculated as:
net_payout = total_confirmed_earnings × (1 - commission_rate / 100)
Drivers do not initiate withdrawals themselves. Payouts are processed manually by the TrustRide admin team based on confirmed booking totals. Drivers can see their total_earnings figure on the dashboard, but the payout transfer is handled off-platform by admin.

Build docs developers (and LLMs) love