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.

TrustRide manages all platform participants through a single custom User model that uses email as the primary identifier. Every account is assigned a role at registration, and that role governs which dashboards, endpoints, and actions are available to the user throughout their session.

Custom User Model

TrustRide extends Django’s AbstractBaseUser with a fully custom User model stored in the users database table. The USERNAME_FIELD is set to email, and the REQUIRED_FIELDS are first_name, last_name, phone, and role.
# apps/users/models.py (key fields)
class User(AbstractBaseUser, PermissionsMixin):
    email        = models.EmailField(unique=True, max_length=255)
    phone        = models.CharField(max_length=15, validators=[validate_phone_number])
    first_name   = models.CharField(max_length=100)
    last_name    = models.CharField(max_length=100)
    gender       = models.CharField(max_length=10, choices=GENDER_CHOICES)
    date_of_birth = models.DateField(null=True, blank=True)
    role         = models.CharField(max_length=10, choices=ROLE_CHOICES, default='rider')

    # Account state flags
    is_active          = models.BooleanField(default=True)
    is_email_verified  = models.BooleanField(default=False)
    is_driver_verified = models.BooleanField(default=False)
    is_suspended       = models.BooleanField(default=False)

    # Financial
    commission_rate = models.DecimalField(max_digits=5, decimal_places=2, default=0.00)

    # Ambassador fields
    is_ambassador              = models.BooleanField(default=False)
    ambassador_status          = models.CharField(max_length=20, choices=[...], default='active')
    ambassador_commission_rate = models.DecimalField(max_digits=5, decimal_places=2, default=5.0)
    ambassador_approved_at     = models.DateTimeField(null=True, blank=True)
    ambassador_approved_by     = models.ForeignKey('self', ...)
    ambassador_notes           = models.TextField(blank=True)

    USERNAME_FIELD  = 'email'
    REQUIRED_FIELDS = ['first_name', 'last_name', 'phone', 'role']
A companion UserProfile model (one-to-one) stores additional optional data: profile picture, home address, next-of-kin details, bank account information, and social media handles.

Phone Number Validation

The phone field is validated by validate_phone_number from apps/core/validators.py. Valid formats are:
08012345678       # local Nigerian format
2348012345678     # international without +
+2348012345678    # international with +

Roles

TrustRide defines three role values on the User model. Role is set at registration and stored permanently on the user record.
RoleDescription
riderBooks intercity trips, uploads payment receipts, rates drivers. Default role.
driverCreates and manages trips, verifies payments, handles refunds. Must be verified by admin before publishing trips.
adminStaff user with full platform access. Created via create_superuser.
A user who registers as a driver can also use the platform as a rider by switching their active session mode. Call GET /switch-mode/<mode>/ with mode=rider, mode=driver, or mode=admin to toggle between dashboards without changing the stored role field.

Account States

Four boolean flags control the lifecycle of every account:
Set to True at registration. When False, the user cannot log in at all. Admin can deactivate accounts from the Django admin panel.
Defaults to False. Set to True via the email activation link (/activate/<uidb64>/<token>/). Riders with unverified email addresses are warned in the dashboard (is_profile_complete() check).
Defaults to False and is only meaningful for users with role=driver. Admin sets this to True after reviewing driver credentials. Unverified drivers cannot publish trips. Attempting to set is_driver_verified=True on a non-driver raises a ValidationError.
Defaults to False. Admin can suspend an account. The custom UserQuerySet exposes .suspended() and .not_suspended() convenience filters. A suspended user’s sessions can be invalidated separately.

Authentication

All authentication is email-based. The platform uses Django’s standard session authentication with a custom authentication form.
1

Register

POST /register/ with email, phone, first_name, last_name, gender, role, and password. A welcome email is dispatched on success. Errors in email delivery do not block account creation.
2

Log In

POST /login/ with email and password. On success, a session cookie is issued and the user is redirected to their role-specific dashboard.
3

Log Out

GET /logout/ (login required). Clears the session and redirects to the homepage.

Password Reset

TrustRide does not use Django’s default email-based password reset. Instead it uses a three-step security-question flow that works entirely within the platform, making it accessible even without a reliable email inbox.
1

Enter Email — /password-reset/

User provides their registered email. The server looks up the account and checks that at least one UserSecurityAnswer exists. The user’s ID is stored in the session. Redirects to step 2.
2

Answer Security Question — /password-reset/question/

The stored security question text is displayed. The user types their answer. The answer is checked against the hashed value via UserSecurityAnswer.check_answer() (Django’s check_password). On success, reset_verified=True is written to the session. Redirects to step 3.
3

Set New Password — /password-reset/confirm/

The session flag reset_verified must be present. User enters and confirms a new password. The password is hashed and saved. Session keys reset_user_id and reset_verified are purged, and the user is redirected to login.
# Security answer model
class UserSecurityAnswer(models.Model):
    user        = models.ForeignKey(User, on_delete=models.CASCADE, related_name='security_answers')
    question    = models.ForeignKey(SecurityQuestion, on_delete=models.CASCADE)
    answer_hash = models.CharField(max_length=128)  # stored via Django's make_password

    def check_answer(self, raw_answer):
        from django.contrib.auth.hashers import check_password
        return check_password(raw_answer, self.answer_hash)

Profile Management

EndpointDescription
GET /profile/View your own profile with trip stats, earnings, and received reviews.
GET/POST /profile/edit/Edit User fields (name, gender, etc.) and UserProfile fields (address, bank details, social handles, next-of-kin).
POST /profile/change-password/Change password using Django’s PasswordChangeForm. Session auth hash is updated to prevent logout.

Ambassador Status Fields

Users who are approved as ambassadors have additional fields set on their User record.
FieldTypeDescription
is_ambassadorBooleanFieldTrue once the application is approved by admin.
ambassador_statusCharFieldOne of active, paused, or revoked.
ambassador_commission_rateDecimalFieldCommission percentage earned per booking (default 5.0%).
ambassador_approved_atDateTimeFieldTimestamp set when admin approves the application.
ambassador_approved_byForeignKey(User)The admin user who approved the application.
ambassador_notesTextFieldInternal admin notes. Not visible to the ambassador.

Explore by Role

Riders

Book seats, track payments, request refunds, and rate drivers.

Drivers

Create trips, manage vehicles, verify payments, and handle refunds.

Ambassadors

Book seats on behalf of others and earn commission per booking.

Bookings

Understand the full booking lifecycle from seat selection to completion.

Build docs developers (and LLMs) love