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 replaces the payment receipt and trip-update workflow that would otherwise happen over WhatsApp or phone calls with a structured, in-app messaging system. Every booking gets its own chat thread between the rider and driver, and a separate notification centre keeps both parties informed about booking events, payment confirmations, waitlist updates, and more.
The chat feature is currently in a “coming soon” state in production. All chat URL patterns currently route to views.coming_soon, which renders a placeholder page. The full chat implementation — including message sending, receipt upload, and WebSocket connectivity — is complete in the codebase and will be activated when the feature is officially launched.

Chat Architecture

TrustRide’s real-time features are built on Django Channels with Redis as the channel layer backend. The ASGI application is configured in trust_ride/asgi.py using ProtocolTypeRouter to handle both HTTP and WebSocket connections.
# trust_ride/asgi.py
application = ProtocolTypeRouter({
    "http": django_asgi_app,
    "websocket": AuthMiddlewareStack(
        URLRouter(
            chat_routing.websocket_urlpatterns
        )
    ),
})
WebSocket connections are authenticated via Django’s AuthMiddlewareStack, which attaches the session user to the WebSocket scope. Unauthenticated connections and connections that fail authorization checks are closed immediately. There are two categories of real-time consumers:

Chat Consumers

Handle per-booking, per-inquiry, and direct user-to-user message threads. Defined in apps/chat/consumers.py.

Notification Consumer

Pushes real-time notification events and unread-count updates to individual users. Defined in apps/notifications/consumers.py.

WebSocket URL Patterns

Chat WebSockets (apps/chat/routing.py)

PatternConsumerDescription
ws/chat/<booking_id>/ChatConsumerPer-booking chat thread between rider and driver
ws/inquiry/<thread_id>/InquiryConsumerPre-booking inquiry thread for a specific trip
ws/direct/<user_id1>/<user_id2>/DirectChatConsumerDirect message channel between any two users
# apps/chat/routing.py
websocket_urlpatterns = [
    re_path(r'ws/chat/(?P<booking_id>[0-9a-f-]+)/$',
            consumers.ChatConsumer.as_asgi()),
    re_path(r'ws/inquiry/(?P<thread_id>[0-9a-f-]+)/$',
            consumers.InquiryConsumer.as_asgi()),
    re_path(r'ws/direct/(?P<user_id1>[0-9a-f-]+)/(?P<user_id2>[0-9a-f-]+)/$',
            consumers.DirectChatConsumer.as_asgi()),
]

Notification WebSocket

The NotificationConsumer uses a per-user group name (notifications_<user_id>) and is instantiated directly. It is not included in the current asgi.py routing but is ready to be wired in when the notifications WebSocket channel is activated. All consumer classes share a BaseChatConsumer that handles connect/disconnect lifecycle, group membership, typing indicator broadcast, and message dispatch. Authorization is enforced by each subclass through the user_is_authorized() async method.

Booking Chat

Each booking gets a dedicated chat thread — a collection of ChatMessage records tied to the Booking — that lives for the duration of the booking’s lifecycle. The chat serves three primary purposes:
  1. Payment verification — the rider uploads their transfer receipt; the driver reviews and confirms
  2. Trip updates — the driver can send messages to the rider about pickup points, timing changes, or instructions
  3. Dispute resolution — in the event of a refund or complaint, the chat thread provides a full audit trail

Accessing a Booking Chat

GET /chat/booking/<uuid:booking_id>/
Access is restricted to the booking’s rider and the trip’s driver. On load, all unread messages are marked as read for the viewing user. The view also calculates the remaining time before the payment reservation expires and passes it to the template for countdown display. The WebSocket channel for a booking chat is identified by the group name chat_<booking_id>. Connect from the client with:
const socket = new WebSocket(`wss://trustride.ng/ws/chat/${bookingId}/`);

Inquiry Chat

Riders can ask questions about a trip before committing to a booking via an inquiry thread. An InquiryThread is unique per (trip, rider, driver) combination, so opening the same inquiry twice returns the existing thread rather than creating a new one.

Starting an Inquiry

GET /chat/inquiry/start/<uuid:trip_id>/
If no thread exists, one is created and an automatic opening message is posted on behalf of the rider:
Hi, I'm interested in your trip from Kaduna to Abuja on Mar 15, 2025.
The rider is then redirected to the inquiry chat view:
GET /chat/inquiry/<uuid:thread_id>/
The corresponding WebSocket group name is inquiry_<thread_id>.

Message Sending

All text messages are sent through a single unified POST endpoint that handles booking threads, inquiry threads, and direct messages based on the provided parameters.
POST /chat/send/
Content-Type: application/x-www-form-urlencoded
ParameterRequiredDescription
booking_idConditionalUUID of the booking (for booking chat)
thread_idConditionalUUID of the inquiry thread (for inquiry chat)
recipient_id + is_direct=trueConditionalTarget user ID for direct messages
messageYesThe message text (cannot be empty)
Exactly one of booking_id, thread_id, or recipient_id+is_direct must be provided. The response is an HTMX partial (chat/_message_list.html) containing the full updated message list, which replaces the message container in the UI without a page reload. After saving the message, the server broadcasts it to the relevant WebSocket group via send_websocket_message:
{
  "type": "message",
  "message_id": "3f8a21bc-...",
  "sender": "Amina Ibrahim",
  "sender_id": "7d9c13ae-...",
  "message": "I just made the transfer",
  "timestamp": "2025-03-15T06:45:00Z",
  "is_system": false
}

Receipt Upload

Riders upload their payment receipt (JPEG, PNG, or PDF, max 5 MB) as a separate action:
POST /chat/upload-receipt/<uuid:booking_id>/
Content-Type: multipart/form-data

receipt_image=<file>
Uploading a receipt:
  • Creates a ChatMessage with receipt_image populated and is_verified=False
  • Changes booking.status to pending_verification
  • Posts a system message: “Receipt uploaded! Awaiting driver verification.”
  • Fires a receipt_uploaded WebSocket event to the booking’s channel

Payment Verification Action

The driver verifies payment directly from within the chat:
POST /chat/verify-payment/<uuid:booking_id>/
This confirms the booking and broadcasts a payment_verified WebSocket event to all connected clients in the chat group.

Notifications

The notifications app (apps/notifications) handles in-app alerts for all platform events. Notifications are created via Notification.objects.create(...) in views and signals throughout the codebase.

Notification Types

TypeWhen It Fires
verificationEmail verification requests
bookingNew booking created on a driver’s trip
paymentPayment approved or rejected
ride_availableA matching trip is published for a FutureTripInterest
waitlistA seat opens up for a waitlisted rider
refundRefund request received, approved, or rejected
reminderPre-trip departure reminder
systemPlatform-wide announcements

Notification Center

The full notification list is accessible at:
GET /notifications/?filter=all
GET /notifications/?filter=unread
GET /notifications/?filter=read
The NotificationCenterView is a LoginRequiredMixin class-based view that queries the authenticated user’s notifications and passes the unread count to the context.

HTMX Integration

TrustRide uses HTMX to update notification and chat UI components in real time without full page reloads.

Live Thread List

GET /chat/htmx/thread-list/
Returns an updated HTML partial (chat/_thread_list.html) containing all booking threads, inquiry threads, and direct message threads for the current user, sorted by most recent activity. Used in the chat inbox sidebar to show unread counts and last message previews.

Notification Count Badge

GET /htmx/notification-count/
Returns the current unread notification count for the authenticated user. Used to update the badge number on the navbar bell icon.

Notification Dropdown

GET /htmx/notification-dropdown/
Returns a partial containing the most recent notifications for display in the navbar dropdown. Polled on a short interval to reflect incoming notifications without a WebSocket.

Mark as Read

Mark a Single Notification

POST /api/notifications/mark-read/
Content-Type: application/x-www-form-urlencoded

notification_id=<uuid>
Sets notification.is_read = True and records read_at = timezone.now().

Mark All Notifications as Read

POST /api/notifications/mark-all-read/
Bulk-updates all unread notifications for the authenticated user to is_read=True in a single query. Both endpoints are also supported over WebSocket via the NotificationConsumer. Clients can send action messages directly through the WebSocket connection:
// Mark a single notification read
{ "action": "mark_read", "notification_id": "3f8a21bc-..." }

// Mark all notifications read
{ "action": "mark_all_read" }

// Request current unread count
{ "action": "get_count" }
The consumer responds with a count_update event containing the latest unread count after each action.

Build docs developers (and LLMs) love