# Intaleq Driver App — Complete Ride Lifecycle Analysis Report ## Table of Contents 1. [System Architecture Overview](#1-system-architecture-overview) 2. [Ride State Machine](#2-ride-state-machine) 3. [Phase 1: Ride Request Ingress (Socket → Order Request)](#3-phase-1-ride-request-ingress) 4. [Phase 2: Accept Order & Navigation to Pickup](#4-phase-2-accept-order--navigation-to-pickup) 5. [Phase 3: Arrival & Begin Ride](#5-phase-3-arrival--begin-ride) 6. [Phase 4: In-Ride Navigation & Polyline System](#6-phase-4-in-ride-navigation--polyline-system) 7. [Phase 5: Finish Ride & Payment](#7-phase-5-finish-ride--payment) 8. [Phase 6: Post-Ride (Rating, Review)](#8-phase-6-post-ride-rating-review) 9. [Pricing Engine](#9-pricing-engine) 10. [Socket.IO Communication](#10-socketio-communication) 11. [HTTP Backend API Endpoints](#11-http-backend-api-endpoints) 12. [Polyline Engine Deep Dive](#12-polyline-engine-deep-dive) 13. [Location Tracking System](#13-location-tracking-system) 14. [Voice Call Signaling](#14-voice-call-signaling) 15. [Key Architectural Patterns & Fixes](#15-key-architectural-patterns--fixes) 16. [Data Flow Diagrams](#16-data-flow-diagrams) --- ## 1. System Architecture Overview ### High-Level Component Map ```mermaid graph TB subgraph "Driver App sefer_driver" A[LocationController] -->|Socket.IO| B[Location Server] C[OrderRequestController] -->|HTTP| D[Ride Server] E[MapDriverController] -->|HTTP| D F[NavigationController] -->|HTTP| G[Map SaaS Server] H[SignalingService] -->|WebSocket| I[Call Server] J[WalletController] -->|HTTP| K[Payment Server] end subgraph "Passenger App Intaleq" L[RideLifecycleController] -->|Polling/HTTP| D M[MapEngineController] -->|HTTP| G end B -->|Socket.IO Events| A B <-->|update_location| A D <-->|Ride CRUD| E D <-->|Ride CRUD| L subgraph "Backend Servers" B[Location Server: location.intaleq.xyz] D[Ride Server: rides.intaleq.xyz] G[Map SaaS: map-saas.intaleqapp.com] I[Call Server: calls.intaleqapp.com] K[Payment Server: walletintaleq.intaleq.xyz] end style A fill:#4a90d9,color:#fff style C fill:#4a90d9,color:#fff style E fill:#4a90d9,color:#fff style F fill:#4a90d9,color:#fff style L fill:#e67e22,color:#fff style M fill:#e67e22,color:#fff ``` ### Server Infrastructure | Server | Base URL | Purpose | |--------|----------|---------| | API Server | `https://api.intaleq.xyz/intaleq_v3` | Auth, CRUD operations, ride management | | Ride Server | `https://rides.intaleq.xyz/intaleq/ride` | Ride-specific CRUD | | Location Server | `https://location.intaleq.xyz` | Socket.IO real-time location, batch uploads, behavior recording | | Map SaaS | `https://map-saas.intaleqapp.com/api/maps/route` | Route/polyline generation | | Payment Server | `https://walletintaleq.intaleq.xyz/v1/main` | Wallet management, payment processing | | Call Server | `wss://calls.intaleqapp.com/ws` | WebRTC signaling for voice/video calls | ### Key Technologies - **State Management**: GetX (`GetxController`) - **Real-time**: Socket.IO (`socket_io_client: 1.0.2`) at `https://location.intaleq.xyz` - **Map**: Custom `intaleq_maps` package (local path: `../map-saas/packages/flutter-sdk/`) - **Routing API**: OSRM-compatible response format via SaaS - **Navigation**: Step-by-step with TTS (`flutter_tts: ^4.0.2`) - **Background**: `flutter_background_service: ^5.1.0`, `flutter_overlay_window: ^0.5.0` --- ## 2. Ride State Machine The driver app uses an implicit state machine managed via a master `status` variable in [`map_driver_controller.dart`](lib/controller/home/captin/map_driver_controller.dart). ```mermaid stateDiagram-v2 [*] --> NoRide: App start / Return to home NoRide --> Searching: Socket new_ride_request received Searching --> DriverApplied: Driver taps Accept Order DriverApplied --> Searching: Ride taken by another driver DriverApplied --> DriverArrived: Driver arrives at pickup point DriverArrived --> InProgress: Driver taps Start Ride / Begin InProgress --> Finished: Driver taps Finish Ride Finished --> PreCheckReview: Driver begins review process PreCheckReview --> NoRide: Review complete / Rate passenger Finished --> NoRide: Skip review note right of NoRide: Location streaming active, listening for orders note right of Searching: OrderRequestPage shown, route calculation note right of DriverApplied: Navigation to passenger pickup point note right of DriverArrived: Waiting timer counting, passenger notified note right of InProgress: Navigation to destination, pricing timer active ``` **State Management Pattern**: The status is stored as a string variable (`status`) and checked throughout with switch/if blocks. Additionally, a `Box` (GetStorage) is used for persistence across app restarts. Key fields in Box include `box.read('status')`, `box.read('ride_id')`, `box.read('tokenPassenger')`. --- ## 3. Phase 1: Ride Request Ingress ### Flow Diagram ```mermaid sequenceDiagram participant S as Location Server Socket.IO participant LC as LocationController participant ORC as OrderRequestController participant UI as OrderRequestPage S->>LC: new_ride_request event Note over LC: Data format: List or Map LC->>LC: handleIncomingOrder() Note over LC: Validate key '16' exists LC->>LC: Extract DriverList structure LC->>LC: Sort by distance LC->>UI: Get.to OrderRequestPage UI->>ORC: initState -> _initializeData() ORC->>ORC: Parse List or Map format ORC->>ORC: _calculateFullJourney() ORC->>MapSaaS: getRoute for pickup + trip MapSaaS-->>ORC: Return polylines + distance + duration ORC->>UI: Update UI with routes ``` ### Socket Event: `new_ride_request` Received in [`location_controller.dart`](lib/controller/functions/location_controller.dart) (lines ~230-323). **Data Payload** (supports **two formats**): **Format A — List** (original): ```dart [ "lat,lng", // [0] start coordinates "lat,lng", // [1] end coordinates "price", // [2] "duration_sec", // [3] trip duration "total_sec", // [4] total duration "distance_m", // [5] trip distance "unknown", // [6] "passenger_id", // [7] "customer_name", // [8] "customer_token", // [9] "phone", // [10] "unknown", // [11] "dist_to_driver_m", // [12] distance to driver "unknown", // [13] "unknown", // [14] "duration_to_driver_sec", // [15] "ride_id", // [16] - Validation key ... "start_address", // [29] "end_address", // [30] "ride_type", // [31] Speed/Comfort/Lady/etc "passenger_rate", // [33] ] ``` **Format B — Map** (newer): ```dart { 'myListString': { ... }, 'DriverList': [ { lat, lng, price, duration, ... }, ... ] } ``` ### Validation Gate ([`location_controller.dart`](lib/controller/functions/location_controller.dart), lines 327-399) ```dart void handleIncomingOrder(dynamic data) { // Check if data has key '16' (ride_id) — if so, treat as List format // Otherwise, extract from myListString/DriverList // Convert all to sorted DriverList format // Navigate to OrderRequestPage } ``` ### Ride Taken Prevention ([`order_request_controller.dart`](lib/controller/home/captin/order_request_controller.dart), lines 624-649) A dedicated socket listener prevents double-accept: ```dart socket.on('ride_taken', (data) { // Check if ride_id matches current displayed order // If so, show "ride taken" dialogue and return to home }); ``` --- ## 4. Phase 2: Accept Order & Navigation to Pickup ### Accept Flow ([`order_request_controller.dart`](lib/controller/home/captin/order_request_controller.dart), lines 672-783) ```mermaid sequenceDiagram participant D as Driver participant ORC as OrderRequestController participant API as Ride Server participant Box as GetStorage participant PDP as PassengerLocationMapPage participant MDC as MapDriverController D->>ORC: Tap Accept ORC->>API: GET acceptRide.php?ride_id=X&driver_id=Y API-->>ORC: Success response ORC->>Box: Write rideArgs: ride_id, status=applied, tokenPassenger, carType, kazan, etc. ORC->>PDP: Get.to(PassengerLocationMapPage, arguments: rideArgs) PDP->>MDC: argumentLoading() parses rideArgs MDC->>Box: Persist all ride data MDC->>MapSaaS: getRoute(for pickup location) MapSaaS-->>MDC: Polyline + steps for driver->passenger route MDC->>MDC: Draw polyline on map MDC->>MDC: Start GPS tracking, step-by-step navigation ``` ### Ride Arguments Map ([`map_driver_controller.dart`](lib/controller/home/captin/map_driver_controller.dart), lines 2212-2279) The complete `rideArgs` map written to Box: | Field | Source | Description | |-------|--------|-------------| | `passenger_lat`, `passenger_lng` | From order data | Passenger pickup location | | `passenger_destination_lat`, `passenger_destination_lng` | From order data | Trip destination | | `ride_id` | From order data | Unique ride identifier | | `tokenPassenger` | From order data | Passenger auth token | | `carType` | Driver profile | Speed/Fixed/Comfort/Lady/Electric/Van/Delivery | | `kazan` | From order data | Commission percentage | | `status` | Set to `applied` | Current ride state | | `price` | From order data | Trip price | | `customerName` | From order data | Passenger name | | `tripDistance` | From order data | Total trip distance | | `tripDurationMin` | Calculated | Trip duration in minutes | --- ## 5. Phase 3: Arrival & Begin Ride ### Arrival Detection The driver's GPS is continuously monitored. When the driver reaches within ~150m of the passenger, the "Arrived" UI state activates. ### Begin Ride ([`map_driver_controller.dart`](lib/controller/home/captin/map_driver_controller.dart), lines 838-952) ```mermaid sequenceDiagram participant D as Driver participant MDC as MapDriverController participant API as Ride Server participant Box as GetStorage participant PSGR as Passenger App D->>MDC: Tap "Begin Ride" / startRideFromDriver() MDC->>MDC: Validate distance from passenger < 150m MDC->>API: GET start_ride.php?ride_id=X&driver_id=Y&passenger_id=Z×tamp=... API-->>MDC: Success MDC->>Box: Update status to 'begin' MDC->>PSGR: Socket emit update_location with status=begin MDC->>MapSaaS: getRoute(for destination, from current location) MapSaaS-->>MDC: New polyline from current pos -> destination MDC->>MDC: Redraw polyline on map MDC->>MDC: Start pricing timer (rideIsBeginPassengerTimer) MDC->>MDC: Start step-by-step navigation ``` **Key Validation**: Distance from passenger must be <150m before ride can begin. This prevents starting the ride prematurely. --- ## 6. Phase 4: In-Ride Navigation & Polyline System ### Full Navigation Stack ```mermaid graph TB subgraph "Navigation System" GPS[Geolocator Stream] --> Filter[Jitter Filter <2m] Filter --> NavCtrl[NavigationController] Filter --> MDC[MapDriverController] NavCtrl --> RouteMatch[RouteMatcherWorker Isolate] NavCtrl --> PolylineDecode[DecodePolylineIsolate] RouteMatch --> SmartSnap[Smart Sliding Window Snapping] SmartSnap --> SplitPoly[Split Traveled vs Upcoming] PolylineDecode --> RouteCoords[Full Route Coordinates] RouteCoords --> StepNav[Step-by-Step Instructions] StepNav --> TTS[Flutter TTS Voice] SplitPoly --> GreyPoly[Grey Traveled Polyline] SplitPoly --> ColorPoly[Colored Upcoming Polyline] end GPS --> Camera[Adaptive Camera] Camera --> Zoom[Speed-Based Zoom: 15-19] Camera --> Tilt[Speed-Based Tilt: 0-55deg] MDC --> Pricing8[Pricing Timer: 1s interval] ``` ### Polyline Rendering (Dual Polyline System) The driver app renders **two polylines simultaneously**: 1. **Upcoming Route** (`polyline` in `MapDriverController`): Colored polyline from the driver's current snapped position to the destination 2. **Traveled Route** (`polyline2` in `MapDriverController`): Grey polyline showing the path already driven ### Smart Sliding Window Snapping ([`map_driver_controller.dart`](lib/controller/home/captin/map_driver_controller.dart), lines 2563-2622) ```dart void _updateTraveledPolylineSmart(LatLng currentLocation) { // 1. Define sliding window of 60 points around last known index // 2. Find closest point on the original route polyline within that window // 3. Split the original route at the matched index: // - Points [0..matchedIndex] -> traveled (grey polyline) // - Points [matchedIndex..end] -> upcoming (colored polyline) // 4. Update map with both polylines } ``` ### Isolate-Based Route Matching ([`route_matcher_worker.dart`](lib/controller/home/navigation/route_matcher_worker.dart)) The heavy computation of finding the closest point on the route polyline is offloaded to a **dedicated isolate**: ``` Messages: init, match, dispose Response: matchResult { index, lat, lng, dist } ``` - Uses **Float64List** for zero-copy memory sharing - Sliding window search (default: 120 points, configurable) - **Haversine distance** for accurate meter-level distance calculation - **Projection onto line segments** for sub-point accuracy ### Step-by-Step Navigation ([`map_driver_controller.dart`](lib/controller/home/captin/map_driver_controller.dart), lines 211-273) ```dart void startListeningStepNavigation() { // 1. Subscribe to Geolocator stream with jitter filter (<2m ignore) // 2. Smooth animation via AnimationController // 3. Snap to route (update traveled polyline) // 4. Check proximity to next step waypoint // 5. If near next waypoint: // - Speak next instruction via TTS // - Update currentStepIndex // - Show next instruction distance // 6. Update camera position (adaptive zoom/tilt based on speed) } ``` **Adaptive Camera**: | Speed | Zoom | Tilt | |-------|------|------| | < 15 km/h | 19 | 0° | | < 40 km/h | 18 | 40° | | < 70 km/h | 17 | 55° | | < 100 km/h | 16 | 55° | | 100+ km/h | 15 | 55° | --- ## 7. Phase 5: Finish Ride & Payment ### Finish Ride Flow ([`map_driver_controller.dart`](lib/controller/home/captin/map_driver_controller.dart), lines 1236-1354) ```mermaid sequenceDiagram participant D as Driver participant MDC as MapDriverController participant API as Ride Server participant PayAPI as Payment Server participant Box as GetStorage D->>MDC: Tap "Finish Ride" Note over MDC: Validate trip distance anti-fraud par Parallel Execution MDC->>API: finish_ride_updates.php MDC->>PayAPI: process_ride_payments.php end API-->>MDC: Ride status updated to finished PayAPI-->>MDC: Payment processed MDC->>MDC: Stop pricing timer MDC->>MDC: Stop navigation / polyline MDC->>Box: Update status to 'finished' MDC->>Box: Save ride price to payment_summary MDC->>MDC: Clear polyline, markers, camera MDC->>MDC: Show ride summary / review UI ``` ### Anti-Fraud Distance Validation ([`map_driver_controller.dart`](lib/controller/home/captin/map_driver_controller.dart), lines ~1290-1330) ```dart _validateTripDistance() { // Actual traveled distance must be >= 1/5 of expected trip distance // If not, auto-reject as potential fraud // This prevents drivers from starting and immediately finishing rides } ``` ### Payment Processing ([`map_driver_controller.dart`](lib/controller/home/captin/map_driver_controller.dart), lines ~1330-1354) - Payment is processed in parallel with ride finish - Payment server generates secure tokens for wallet transactions - Supports: Stripe, PayMob, MTN, Syriatel, eCash, ShamCash --- ## 8. Phase 6: Post-Ride (Rating, Review) After finishing, the driver enters the `preCheckReview` state: 1. **Rating**: Rate the passenger (`addRateToPassenger.php`) 2. **Review Screen**: `ride_calculate_driver.dart` shows: - Trip price breakdown - Commission (kazan%) - Net earnings - Distance/time summary 3. **Return to Home**: Status reset to `noRide`, ready for next order --- ## 9. Pricing Engine ### Core Pricing Timer ([`map_driver_controller.dart`](lib/controller/home/captin/map_driver_controller.dart), lines 1481-1570) ```dart void rideIsBeginPassengerTimer() { Timer.periodic(Duration(seconds: 1), (timer) { // 1. Calculate distance delta since last tick // 2. Fetch current car type pricing config // 3. Apply time-of-day multiplier // 4. Apply distance-based thresholds // 5. Apply airport surcharge if applicable // 6. Calculate commission (kazan%) // 7. Update live price display }); } ``` ### Price Calculation Formula ([`map_driver_controller.dart`](lib/controller/home/captin/map_driver_controller.dart), lines 1572-1662) ```dart double _calculateCurrentPrice() { // Base price depends on carType: // Speed, Fixed, Comfort, Lady, Electric, Van, Delivery // // Time-of-day bands: // nature (normal), late (evening/night), heavy (peak) // // Distance thresholds: // 25km, 35km, 40km - different pricing tiers // // Commission: kazan% taken by platform // // Airport contexts: additional surcharge // // Formula (simplified): // basePrice = carType.baseRate * timeMultiplier // distancePrice = distance * carType.perKmRate // if distance > 25km: apply longTripMultiplier // if airport: add airportSurcharge // finalPrice = (basePrice + distancePrice) * (1 + kazan/100) } ``` --- ## 10. Socket.IO Communication ### Connection Setup ([`location_controller.dart`](lib/controller/functions/location_controller.dart), lines 183-228) ```dart void initSocket() { socket = io( 'https://location.intaleq.xyz', { 'transports': ['websocket'], // WebSocket-only transport 'query': { 'driver_id': driverId, 'token': authToken, }, }, ); } ``` ### Events Summary | Event | Direction | Frequency | Purpose | |-------|-----------|-----------|---------| | `new_ride_request` | Server → Driver | On demand | Incoming ride request | | `ride_taken` | Server → Driver | On demand | Ride accepted by another driver | | `cancel_ride` | Server → Driver | On demand | Passenger cancelled the ride | | `update_location` | Driver → Server | Every 5-10s | Driver location broadcast | | `connect` | Bidirectional | On connect | Socket established | | `disconnect` | Bidirectional | On disconnect | Socket lost | | Heartbeat (ping/pong) | Bidirectional | Every 25s | Keep-alive | ### Cancel Ride Handler ([`map_driver_controller.dart`](lib/controller/home/captin/map_driver_controller.dart), lines 339-410) ```dart void processRideCancelledByPassenger() { // Gatekeeper: stop all timers immediately (Fix 2) // Stop: pricingTimer, waitingTimer, navigation // Show cancellation dialog // Clear ride data from Box // Reset status to noRide // Return to HomeCaptain } ``` ### Location Upload ([`location_controller.dart`](lib/controller/functions/location_controller.dart), lines 420-453) ```dart void emitLocationToSocket() { Map data = { 'driver_id': driverId, 'lat': currentLat, 'lng': currentLng, 'heading': heading, 'speed': speed, 'status': currentStatus, 'distance': distance, }; // If ride active, inject passenger_id and ride_id if (rideActive) { data['passenger_id'] = passengerId; data['ride_id'] = rideId; } socket.emit('update_location', data); } ``` --- ## 11. HTTP Backend API Endpoints ### Ride Lifecycle Endpoints | Endpoint | Method | Phase | Purpose | |----------|--------|-------|---------| | [`acceptRide.php`](lib/constant/links.dart) | GET | Accept | Driver accepts ride offer | | [`start_ride.php`](lib/constant/links.dart) | GET | Begin | Start the ride trip | | [`finish_ride_updates.php`](lib/constant/links.dart) | GET | Finish | Complete ride (parallel) | | [`process_ride_payments.php`](lib/constant/links.dart) | GET | Finish | Process payment (parallel) | | [`cancelRide/add.php`](lib/constant/links.dart) | POST | Any | Log cancellation | | [`addCancelTripFromDriverAfterApplied.php`](lib/constant/links.dart) | POST | Applied | Driver cancels after accepting | ### Ride Data Endpoints | Endpoint | Method | Purpose | |----------|--------|---------| | [`rides/add.php`](lib/constant/links.dart) | POST | Create ride record | | [`rides/get.php`](lib/constant/links.dart) | GET | Retrieve ride details | | [`rides/update.php`](lib/constant/links.dart) | POST | Update ride status | | [`rides/delete.php`](lib/constant/links.dart) | DELETE | Remove ride record | | [`getRideStatus.php`](lib/constant/links.dart) | GET | Check ride status | | [`getRideOrderID.php`](lib/constant/links.dart) | GET | Get order ID for ride | | [`updateRideAndCheckIfApplied.php`](lib/constant/links.dart) | POST | Atomic status check + update | | [`getRideStatusFromStartApp.php`](lib/constant/links.dart) | GET | Recover ride status on app start | ### Location Endpoints | Endpoint | Method | Purpose | |----------|--------|---------| | [`add_batch.php`](lib/constant/links.dart) | POST | Batch location upload | | [`save_behavior.php`](lib/constant/links.dart) | POST | Record driving behavior | | [`get.php`](lib/constant/links.dart) | GET | Get car locations | | [`getRidesDriverByDay.php`](lib/constant/links.dart) | GET | Daily ride history | | [`getTotalDriverDuration.php`](lib/constant/links.dart) | GET | Total driving time | ### Map SaaS Endpoint | Endpoint | Method | Purpose | |----------|--------|---------| | `https://map-saas.intaleqapp.com/api/maps/route` | POST | Route calculation with polyline | | `https://map-saas.intaleqapp.com/api/geocoding/places` | POST | Place search/geocoding | **Route API Response Format** (OSRM-compatible): ```json { "routes": [{ "geometry": { "coordinates": [[lng, lat], ...], "points": "encoded_polyline_string" }, "legs": [{ "steps": [ { "maneuver": { "location": [lng, lat], "modifier": "straight" }, "instruction": "Continue straight on Main St", "distance": 123.4, "duration": 45.6 } ], "distance": 5000.0, "duration": 600.0 }], "distance": 5000.0, "duration": 600.0 }] } ``` ### Payment Endpoints | Endpoint | Method | Purpose | |----------|--------|---------| | [`payment/add.php`](lib/constant/links.dart) | POST | Record payment | | [`payment/get.php`](lib/constant/links.dart) | GET | Get today's payments | | [`getAllPaymentFromRide.php`](lib/constant/links.dart) | GET | All payments for a ride | | [`addPaymentTokenDriver.php`](lib/constant/links.dart) | POST | Generate payment token | | [`payWithPayMobCardDriver.php`](lib/constant/links.dart) | POST | PayMob card payment | | [`payWithWallet.php`](lib/constant/links.dart) | POST | Wallet payment | | [`payWithMTNConfirm.php`](lib/constant/links.dart) | POST | MTN payment confirmation | | [`payWithSyriatelConfirm.php`](lib/constant/links.dart) | POST | Syriatel payment confirmation | --- ## 12. Polyline Engine Deep Dive ### Polyline Decoding ([`decode_polyline_isolate.dart`](lib/controller/home/navigation/decode_polyline_isolate.dart)) Standard Google Encoded Polyline Format v5: ```dart List decodePolylineIsolate(String encoded) { // Standard algorithm: // 1. Read 5-bit chunks from charCode - 63 // 2. Reconstruct signed value using ZigZag decoding // 3. Accumulate lat/lng and divide by 1E5 // 4. Add to points list } ``` Runs in **separate isolate** via `compute(PolylineUtils.decode, ...)` to avoid jank. ### Route Fetching ([`order_request_controller.dart`](lib/controller/home/captin/order_request_controller.dart), lines 341-405) ```dart Future> _fetchRouteData(LatLng from, LatLng to) async { // 1. POST to AppLink.mapSaasRoute with coordinates // 2. Parse OSRM-style response // 3. Decode polyline via compute(_decodePolyline, ...) // 4. Return {distance, duration, polyline, steps} } ``` ### Dual Polyline System (Visual) ``` Before traveling: [Passenger] ============================================> [Destination] (Full route in blue/colored) During travel: [Driver] ~~~~~~~~~~> [Current Position] ===============> [Destination] (Grey traveled) (Colored upcoming) ``` ### Smart Snapping Visualization ``` Original route points: P0 --- P1 --- P2 --- P3 --- P4 --- P5 --- P6 --- P7 --- P8 Driver at position X (near P2-P3 segment): Sliding window: [P0---P1---P2---P3---P4---P5] (window=60) Closest projection: on segment P2-P3 at point C Result: Traveled: P0---P1---P2---C (grey) Upcoming: C---P3---P4---P5---P6---P7---P8 (colored) ``` --- ## 13. Location Tracking System ### Dual-Interval Architecture ([`location_controller.dart`](lib/controller/functions/location_controller.dart)) ```mermaid graph LR subgraph "Normal Mode" GPS3[GPS every 5s] --> Record3[Record to buffer every 3s] Record3 --> Upload2[Upload batch every 2min] Upload2 --> Socket[Socket.IO emit] Upload2 --> HTTP[HTTP batch upload] end subgraph "Power Save Mode" GPS10[GPS every 10s] --> Record10[Record to buffer every 10s] Record10 --> Upload5[Upload batch every 5min] Upload5 --> Socket Upload5 --> HTTP end ``` ### Behavior Recording In addition to location, the system records **driving behavior**: - Acceleration/deceleration events - Speed threshold violations - Uploaded to `save_behavior.php` ### Battery Optimization - **Wakelock**: Maintained during active rides (`wakelock_plus`) - **Background Service**: `flutter_background_service` keeps location streaming alive - **Overlay Window**: `flutter_overlay_window` shows driver status even when app is backgrounded --- ## 14. Voice Call Signaling ### WebSocket Signaling ([`signaling_service.dart`](lib/services/signaling_service.dart)) ```mermaid sequenceDiagram participant D as Driver App participant WS as WebSocket wss://calls.intaleqapp.com/ws participant P as Passenger App D->>WS: authenticate { session_id, user_id } WS-->>D: authenticated P->>WS: authenticate { session_id, user_id } WS-->>P: authenticated P->>WS: call_request { target_user_id } WS->>D: participant_joined { user_id } D->>WS: offer { sdp } WS->>P: offer { sdp } P->>WS: answer { sdp } WS->>D: answer { sdp } D->>WS: ice_candidate { candidate } WS->>P: ice_candidate { candidate } P->>WS: ice_candidate { candidate } WS->>D: ice_candidate { candidate } Note over D,P: WebRTC Peer Connection established D->>WS: call_ended WS->>P: call_ended ``` --- ## 15. Key Architectural Patterns & Fixes ### Documented Fixes | Fix | Issue | Solution | |-----|-------|----------| | Fix 1 | Two competing GPS listeners | Merged into single stream subscription | | Fix 2 | Timer leak on cancel | Stop ALL timers immediately at gatekeeper | | Fix 3 | Polyline decode blocking UI | Moved to `compute()` isolate | | Fix 4 | Wrong distance unit in validation | Fixed `_validateTripDistance()` unit conversion | | Fix 5 | `Future.delayed` without `await` | Added proper `await` | | Fix 6 | Redundant heartbeat during stream | Skip heartbeat if location stream active | ### Architecture Patterns 1. **Controller-per-Screen**: Each screen has its own `GetxController` 2. **Box Persistence**: GetStorage used for ride state recovery across app restarts 3. **Socket Decoupling**: Location data flows through Socket.IO, but ride CRUD uses HTTP REST 4. **Isolate Offloading**: Heavy polyline operations run in isolates via `compute()` 5. **Parallel Execution**: Finish ride + payment run concurrently via `Future.wait` 6. **Dual Data Format Support**: Socket data arrives as either List or Map — both handled 7. **Gatekeeper Pattern**: Cancellation handler stops all active processes at a single entry point --- ## 16. Data Flow Diagrams ### Complete Ride Lifecycle Data Flow ```mermaid graph TB subgraph "Pre-Ride" A[Socket: new_ride_request] --> B[Parse List/Map] B --> C[OrderRequestPage] C --> D[Driver Accepts] D --> E[HTTP: acceptRide.php] E --> F[Write rideArgs to Box] F --> G[Navigate to Map] end subgraph "To-Passenger" G --> H[Route: Driver -> Passenger] H --> I[Drew colored polyline] I --> J[Step Nav + TTS] J --> K[GPS updates every 5s] K --> L[Socket: update_location] L --> M[Smart snap to route] end subgraph "At Passenger" M --> N[Arrive ~150m] N --> O[HTTP: start_ride.php] O --> P[Redraw route -> Destination] end subgraph "To-Destination" P --> Q[Pricing Timer 1s] Q --> R[Live price display] R --> S[Step Nav + TTS] S --> T[Dual polyline: grey + colored] T --> U[Socket: update_location with status] end subgraph "Finish" U --> V[HTTP: finish_ride_updates.php] V --> W[HTTP: process_ride_payments.php] W --> X[Stop all timers] X --> Y[Clear polylines] Y --> Z[Show summary / rating] Z --> AA[Reset to noRide] end style A fill:#e74c3c,color:#fff style O fill:#2ecc71,color:#fff style V fill:#2ecc71,color:#fff style W fill:#2ecc71,color:#fff style AA fill:#3498db,color:#fff ``` ### Socket Event Flow During Ride ```mermaid sequenceDiagram participant Driver participant LS as Location Server participant PSGR as Passenger App Note over Driver: Searching for ride LS->>Driver: new_ride_request { data } Driver->>LS: update_location { status: searching } Note over Driver: Ride accepted Driver->>LS: update_location { status: applied, ride_id } Note over Driver: En route to passenger Driver->>LS: update_location { lat, lng, heading, speed, status: goingToPassenger } LS->>PSGR: driverLocationUpdate { ... } Note over Driver: Arrived at passenger Driver->>LS: update_location { status: arrived } Note over Driver: Ride started Driver->>LS: update_location { status: inProgress, ride_id } Note over Driver: En route to destination Driver->>LS: update_location { lat, lng, heading, speed, status: inProgress } LS->>PSGR: driverLocationUpdate { ... } Note over Driver: Ride finished Driver->>LS: update_location { status: finished } Note over Driver: Back to idle Driver->>LS: update_location { status: online } ``` ### Key Backend Endpoints Used Per Phase | Phase | Endpoint | Purpose | |-------|----------|---------| | Accept | `acceptRide.php?ride_id=X&driver_id=Y` | Accept ride | | Begin | `start_ride.php?ride_id=X&driver_id=Y&passenger_id=Z` | Start trip | | In-Ride | `update_location` (Socket) | Location streaming | | In-Ride | `updateRideAndCheckIfApplied.php` | Status sync | | In-Ride | `getKazanPercent.php` | Commission config | | Finish | `finish_ride_updates.php` | Complete ride | | Finish | `process_ride_payments.php` | Payment processing | | Finish | `addRateToPassenger.php` | Passenger rating | | Post-Ride | `getAllPaymentFromRide.php` | Payment summary | | Any | `getRideStatusFromStartApp.php` | State recovery on restart | --- ## Appendix: Key File Reference | File | Lines | Purpose | |------|-------|---------| | [`lib/controller/home/captin/map_driver_controller.dart`](lib/controller/home/captin/map_driver_controller.dart) | 2644 | Core driver ride lifecycle, navigation, polyline, pricing | | [`lib/controller/home/captin/order_request_controller.dart`](lib/controller/home/captin/order_request_controller.dart) | 828 | Ride request handling, accept logic, route display | | [`lib/controller/functions/location_controller.dart`](lib/controller/functions/location_controller.dart) | 794 | Socket.IO, location tracking, batch upload, behavior | | [`lib/controller/home/navigation/navigation_controller.dart`](lib/controller/home/navigation/navigation_controller.dart) | 1383 | Step-by-step navigation, route matching, alternative routes | | [`lib/controller/home/navigation/route_matcher_worker.dart`](lib/controller/home/navigation/route_matcher_worker.dart) | 146 | Isolate-based route matching with sliding window | | [`lib/controller/home/navigation/decode_polyline_isolate.dart`](lib/controller/home/navigation/decode_polyline_isolate.dart) | 32 | Polyline decode in isolate | | [`lib/models/model/order_data.dart`](lib/models/model/order_data.dart) | 188 | Order data model (List + Map constructors) | | [`lib/constant/links.dart`](lib/constant/links.dart) | 424 | All backend API endpoints | | [`lib/services/signaling_service.dart`](lib/services/signaling_service.dart) | 112 | WebRTC call signaling | | [`lib/services/offline_map_service.dart`](lib/services/offline_map_service.dart) | - | Offline map tile service | | [`pubspec.yaml`](pubspec.yaml) | 144 | Dependencies and package config |