TrustRide is organised as a monolithic Django project with eight focused internal apps, each owning a single domain of the platform. The project root isDocumentation 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.
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 underapps/ 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 withseat_layout(JSON), plate-number validation, and type choices (sedan, SUV, minivan, bus, etc.)Trip— published journey withorigin,destination,stops(JSON),pickups/dropoffs(JSON for dynamic pricing),gender_restriction,statuslifecycle (draft → published → in_progress → completed), and DB indexes on(origin, destination, departure_date)for search performanceBooking— seat reservation linking a rider to a specificseat_idon a trip;unique_together = ['trip', 'seat_id']enforces exclusivity;payment_expiryis auto-set fromAppSetting.get_setting('booking_expiry_minutes', 30)GPSLog— individual coordinate records with speed and ais_deviationflagDeviationAlert— raised when GPS processing detects the driver has strayed from the route; tracked throughactive → resolved/ignoredwith admin assignmentRating— bidirectional post-trip rating between driver and rider;unique_together = ['trip', 'reviewer', 'reviewee']prevents duplicate reviewsDriverReport— 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 bothUUIDModel (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:
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 intrust_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):
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:
- Validates on
connect()that the connecting user matches theuser_idin the URL — unauthenticated or mismatched connections are rejected immediately. - Joins the group
notifications_{user_id}in the channel layer. - Listens for
mark_read,mark_all_read, andget_countactions from the client. - Pushes
new_notificationandcount_updatemessage 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 anddjango-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:
| Task | Module | Interval | What it does |
|---|---|---|---|
expire_bookings_and_cleanup | apps.chat.tasks | Every 120 s | Calls 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_statuses | apps.rides.tasks | Every 60 s | Advances 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. |
.delay() calls includes sending booking confirmation emails, dispatching notifications when waitlist seats become available, and pushing WebSocket events to affected users after state changes.
Request Lifecycle: Booking a Seat
Understanding how a booking flows end-to-end helps when debugging state mismatches or extending the platform:- HTMX form submission — The rider selects a seat from the visual seat map and submits an HTMX
POSTrequest to the booking creation view inapps/rides/views.py. - Django view — The view validates seat availability (queries
Bookingwithstatus__in=['reserved', 'confirmed']for the trip), creates a newBookingwithstatus='reserved', and calculatespayment_expiryfromAppSetting.get_setting('booking_expiry_minutes', 30). - Model save —
Booking.save()auto-setspayment_expiryif not provided, then the ORM writes the row.unique_together = ['trip', 'seat_id']raisesIntegrityErrorif a race condition slips through the view-layer check. - Celery task — The
expire_bookings_and_cleanupbeat task runs every 120 seconds and callsrelease_expired_bookings(), which finds allreservedbookings past theirpayment_expiryand flips their status toexpired, returning the seat to the available pool. - WebSocket notification — When the booking is confirmed (driver marks receipt verified), a Django signal fires, creates a
Notificationrecord, and callschannel_layer.group_send()on the rider’snotifications_{user_id}group. The rider’s open browser tab receives thenew_notificationevent 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.