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 is organised as a monolithic Django project with eight focused internal apps, each owning a single domain of the platform. The project root is trust_ride/, which holds settings.py, urls.py, and asgi.py. All business logic lives under the apps/ directory. The stack is Django 6 + Daphne (ASGI) + Django Channels 4 + Celery 5 + PostgreSQL + Redis.

App Structure

Every app under apps/ is registered in INSTALLED_APPS inside settings.py and follows the standard Django layout: models.py, views.py, urls.py, admin.py, and migrations/. The responsibilities are cleanly separated:

apps/core

Shared infrastructure for every other app. Provides two abstract base models — TimeStampedModel (created_at, updated_at) and UUIDModel (UUID primary key) — that are mixed into nearly every concrete model in the codebase. Also contains AppSetting, a key-value store for runtime configuration (e.g., the booking_expiry_minutes setting that controls how long a seat reservation stays open before the Celery task reclaims it), context_processors.py for global template context, and shared utility helpers in core/utils/.

apps/users

Custom authentication layer. User extends AbstractBaseUser and PermissionsMixin with email as USERNAME_FIELD. The model carries the role field (rider, driver, admin), driver-verification flags (is_driver_verified, is_email_verified), ambassador fields (is_ambassador, ambassador_status, ambassador_commission_rate), and commission tracking. UserProfile is a OneToOneField extension holding profile pictures, next-of-kin contacts, social-media handles, and bank account details used for payouts. AmbassadorApplication manages the approval pipeline from rider to ambassador.

apps/rides

The core booking domain. Contains the following models:
  • Vehicle — driver’s vehicle with seat_layout (JSON), plate-number validation, and type choices (sedan, SUV, minivan, bus, etc.)
  • Trip — published journey with origin, destination, stops (JSON), pickups/dropoffs (JSON for dynamic pricing), gender_restriction, status lifecycle (draft → published → in_progress → completed), and DB indexes on (origin, destination, departure_date) for search performance
  • Booking — seat reservation linking a rider to a specific seat_id on a trip; unique_together = ['trip', 'seat_id'] enforces exclusivity; payment_expiry is auto-set from AppSetting.get_setting('booking_expiry_minutes', 30)
  • GPSLog — individual coordinate records with speed and a is_deviation flag
  • DeviationAlert — raised when GPS processing detects the driver has strayed from the route; tracked through active → resolved/ignored with admin assignment
  • Rating — bidirectional post-trip rating between driver and rider; unique_together = ['trip', 'reviewer', 'reviewee'] prevents duplicate reviews
  • DriverReport — rider-submitted safety or conduct report with a moderation pipeline (pending → reviewed → resolved/dismissed)
  • AmbassadorTripApproval — grants a specific ambassador permission to book seats on a specific trip

apps/payments

Handles the financial side of completed bookings. Payout tracks what a driver is owed after the platform commission is deducted (amount, commission, net_amount), holds a ManyToManyField to the Booking records that make up the payout period, and moves through pending → processing → completed/failed. A separate Refund model (referenced in the Celery task) handles cancellation refunds. Payment reference verification logic lives in this app’s views.

apps/chat

Real-time messaging backed by Django Channels. ChatMessage links to either a Booking (for payment verification threads) or an InquiryThread (pre-booking Q&A between a rider and driver). Messages can carry a receipt_image upload — this is the primary mechanism for manual bank-transfer payment proof. Three WebSocket consumers (ChatConsumer, InquiryConsumer, DirectChatConsumer) are defined in consumers.py and registered in routing.py.

apps/notifications

Platform-wide event notifications. Notification objects are created by Django signals (signals.py) on booking status changes, payment verification events, and trip updates. NotificationConsumer (in consumers.py) is an async WebSocket consumer that pushes new notifications to the logged-in user’s browser tab in real time and handles mark_read, mark_all_read, and get_count actions.

apps/interest

Demand-sensing layer. FutureTripInterest lets riders register route-and-date interest before a trip exists; when a driver publishes a matching trip, a background task notifies all registered riders. WaitlistEntry manages the ordered queue for fully-booked trips — riders join the queue, and when a booking is cancelled or expires, the next eligible waiter is notified and given a time-limited window to claim the seat.

apps/admin_panel

Custom operations dashboard at /control/. Provides views for driver verification, payout processing, deviation alert resolution, dispute handling, and platform analytics. Exposes its own context_processors.py for sidebar counts (pending verifications, open reports, pending payouts). This is separate from Django’s built-in /admin/ — the built-in admin is still registered but the custom panel is the day-to-day operations interface.

Data Model Overview

Every domain model inherits from both UUIDModel (UUID primary key) and TimeStampedModel (created_at, updated_at), providing a consistent audit trail across the entire schema. The key relationships flow from User outward:
User (apps/users)

├── role = 'driver'
│   ├── Vehicle  [FK: driver]          Vehicle image, seat_layout JSON
│   └── Trip     [FK: driver]          origin, destination, status, gender_restriction
│       ├── Booking   [FK: trip, rider] seat_id, price, status, payment_expiry
│       │   ├── ChatMessage [FK: booking] receipt_image, is_verified
│       │   └── Payout      [M2M: bookings] amount, commission, net_amount
│       ├── GPSLog    [FK: trip]        lat, lng, speed, is_deviation
│       ├── DeviationAlert [FK: trip]  deviation_amount, status
│       ├── WaitlistEntry  [FK: trip]  queue_position, expires_at
│       └── Rating    [FK: trip]       reviewer, reviewee, rating (1–5)

├── role = 'rider'
│   ├── Booking           [FK: rider]
│   ├── FutureTripInterest            origin, destination, preferred_date
│   └── WaitlistEntry

└── is_ambassador = True
    ├── AmbassadorApplication         status, admin review
    └── AmbassadorTripApproval        per-trip booking permission
The Booking model is the central join: it links a User (rider) to a Trip (owned by a driver), carries the financial record (price, payment_expiry), hosts the payment-verification chat thread via ChatMessage, and is the foreign key for Payout records.

WebSocket Architecture

TrustRide uses Django Channels 4 with a Redis channel layer for horizontal scalability. The ASGI application is assembled in trust_ride/asgi.py using ProtocolTypeRouter: HTTP requests are handled by the standard Django ASGI app, and WebSocket connections are routed through AuthMiddlewareStack (which injects the Django session user into the WebSocket scope) then dispatched to consumers. Chat consumers (apps/chat/routing.py):
ws/chat/<booking_id>/          → ChatConsumer
ws/inquiry/<thread_id>/        → InquiryConsumer
ws/direct/<user_id1>/<user_id2>/  → DirectChatConsumer
Notification consumer (apps/notifications/consumers.py) defines NotificationConsumer, which operates on user-scoped channel groups named notifications_{user_id}. The consumer class is implemented but is not currently wired into the ASGI router — trust_ride/asgi.py routes only chat_routing.websocket_urlpatterns. Notifications are delivered to connected chat sessions and via HTMX polling endpoints (/htmx/notification-dropdown/, /htmx/notification-count/) instead. The consumer class:
  1. Validates on connect() that the connecting user matches the user_id in the URL — unauthenticated or mismatched connections are rejected immediately.
  2. Joins the group notifications_{user_id} in the channel layer.
  3. Listens for mark_read, mark_all_read, and get_count actions from the client.
  4. Pushes new_notification and count_update message types back to the browser.
The default settings.py uses InMemoryChannelLayer for development simplicity. For full WebSocket broadcast (especially for the notification fan-out pattern), switch to channels_redis.core.RedisChannelLayer by updating the CHANNEL_LAYERS setting and pointing it at your REDIS_URL. The channels_redis package is already in requirements.txt.

Celery Task Architecture

TrustRide uses Celery 5 with Redis as the broker and django-celery-beat for schedule persistence. Beat schedules are stored in the database (DatabaseScheduler), so you can adjust task intervals from the Django admin without redeploying. Two tasks are registered in CELERY_BEAT_SCHEDULE:
TaskModuleIntervalWhat it does
expire_bookings_and_cleanupapps.chat.tasksEvery 120 sCalls release_expired_bookings() to reclaim seats from expired reserved bookings, archives inactive inquiry threads older than 7 days, and deletes chat messages older than 30 days (excluding those linked to open refunds).
update_trip_statusesapps.rides.tasksEvery 60 sAdvances published trips to in_progress when departure time is reached, and advances in_progress trips to completed when estimated_arrival_time is passed. Also marks all confirmed bookings on completed trips as completed.
Additional background work fired by model signals or direct .delay() calls includes sending booking confirmation emails, dispatching notifications when waitlist seats become available, and pushing WebSocket events to affected users after state changes.
Run celery -A trust_ride inspect active while processing is underway to see currently executing tasks. Use celery -A trust_ride inspect scheduled to verify beat tasks are queued correctly. If beat tasks are not firing, confirm the Beat process is started with --scheduler django_celery_beat.schedulers:DatabaseScheduler and that you have run python manage.py migrate so the django_celery_beat tables exist.

Request Lifecycle: Booking a Seat

Understanding how a booking flows end-to-end helps when debugging state mismatches or extending the platform:
  1. HTMX form submission — The rider selects a seat from the visual seat map and submits an HTMX POST request to the booking creation view in apps/rides/views.py.
  2. Django view — The view validates seat availability (queries Booking with status__in=['reserved', 'confirmed'] for the trip), creates a new Booking with status='reserved', and calculates payment_expiry from AppSetting.get_setting('booking_expiry_minutes', 30).
  3. Model saveBooking.save() auto-sets payment_expiry if not provided, then the ORM writes the row. unique_together = ['trip', 'seat_id'] raises IntegrityError if a race condition slips through the view-layer check.
  4. Celery task — The expire_bookings_and_cleanup beat task runs every 120 seconds and calls release_expired_bookings(), which finds all reserved bookings past their payment_expiry and flips their status to expired, returning the seat to the available pool.
  5. WebSocket notification — When the booking is confirmed (driver marks receipt verified), a Django signal fires, creates a Notification record, and calls channel_layer.group_send() on the rider’s notifications_{user_id} group. The rider’s open browser tab receives the new_notification event in real time without a page reload.

Explore Key Features

Rides & Bookings

Trip lifecycle, seat reservation expiry, and payment status machine.

Chat & Payments

WebSocket consumers, receipt upload flow, and manual verification.

GPS Tracking

GPSLog ingestion, deviation detection, and real-time alerts.

Users & Roles

Custom user model, driver verification, and ambassador program.

Build docs developers (and LLMs) love