Karpool Workflow Documentation

This documentation provides comprehensive workflow-based guidance for the Karpool application, focusing on how users interact with the system and how the technical components work together to deliver a seamless carpooling experience.

Documentation Structure:
  • Carpool Workflows: Creating, updating, and managing carpools
  • Ride Workflows: Starting, tracking, and completing rides
  • Technical Architecture: System components and their interactions
  • API Reference: Technical implementation details

Carpool Workflows

Carpool workflows cover the complete lifecycle of creating, managing, and updating carpools. These workflows ensure that carpool organizers can set up reliable transportation arrangements for their groups.

Create Carpool Workflow

Phase 1: User Authentication & Access

  1. User opens the Karpool app
  2. System checks authentication status
  3. If not authenticated, user is prompted to sign in with Google
  4. Upon successful authentication, user gains access to carpool creation

Phase 2: Carpool Creation Form

Users fill out a comprehensive form to create their carpool. The form is designed to be user-friendly while capturing all necessary information.

📝 Basic Information

Carpool Name - Give your carpool a memorable name (e.g., "Downtown Commute", "School Run")

Description - Optional details about the carpool (e.g., "Morning commute to downtown office")

📍 Location Details

Pickup Location - Where passengers will be picked up

Dropoff Location - Where passengers will be dropped off

Note: The system automatically finds GPS coordinates and parses address components (street, city, state, etc.)

📅 Schedule & Timing

Start Date - When the carpool begins (optional)

End Date - When the carpool ends (optional)

Pickup Time - Preferred pickup time (optional)

Dropoff Time - Preferred dropoff time (optional)

Recurring Days - Which days of the week (Monday, Tuesday, etc.)

👥 Participation

Max Participants - Maximum number of people (default: 4)

Note: You are automatically added as the admin when you create the carpool

Phase 3: Smart Location Processing

When you enter addresses, the system automatically processes them to ensure accuracy and completeness.

🔍 What Happens Behind the Scenes

  • Address Validation - Google Places API verifies your addresses are real
  • GPS Coordinates - Exact latitude and longitude are calculated automatically
  • Address Parsing - Street number, street name, city, state, and postal code are extracted
  • Location Reference - Unique place IDs are stored for future use

✨ User Experience

  • Just type in addresses like "123 Main St, Anytown, CA"
  • The system handles all the technical details
  • You can add custom location names (e.g., "Office Building", "School Entrance")
  • Full addresses are stored for easy display to participants

Phase 4: Creating Your Carpool

Once you've filled out the form, the system creates your carpool with all the necessary details.

✅ Validation & Security

  • Required Fields Check - Ensures carpool name and addresses are provided
  • Location Verification - Confirms GPS coordinates are available
  • User Authentication - Verifies you're logged in and authorized
  • Participant Limits - Ensures max participants is a valid number

🚀 What Happens Next

  1. Form Submission - Your carpool data is securely sent to the server
  2. Database Creation - A new carpool record is created with all your details
  3. Admin Assignment - You're automatically set as the carpool administrator
  4. Unique ID Generation - A 6-character code is created for your carpool
  5. Success Confirmation - You see a confirmation that your carpool was created

Phase 5: After Creation

Once your carpool is created, you can start managing it and inviting participants.

📱 Immediate Actions

  • View in App - Your carpool appears in "My Carpools" list
  • Share with Others - Get a share link to invite participants
  • Manage Settings - Update details, add schedules, or modify settings

⚙️ Automatic Setup

  • Recurring Schedule - If you specified recurring days, the system sets up the schedule
  • Notification Setup - Participants will receive notifications for carpool updates
  • Admin Permissions - You have full control over the carpool as the creator
Technical Implementation:
  • API Endpoint: POST /rest/v1/carpools
  • Request Body: CreateCarpoolRequest with granular address components
  • Database Tables: carpools, carpool_participants
  • Validation: Required field validation, GPS coordinate validation, participant limits
  • Error Handling: Enhanced error handling with AppError types and user-friendly messages
  • Address System: Granular address components (street, city, state, postal code) + full formatted addresses
  • ID Generation: 6-character alphanumeric carpool IDs

Update Carpool Workflow

As a carpool administrator, you can update your carpool details at any time. The system ensures only authorized users can make changes.

🔐 Who Can Update

  • Admin Only - Only the carpool creator (admin) can make updates
  • Automatic Detection - The system automatically checks if you're the admin
  • Secure Access - Update options are only shown to authorized users

📝 What You Can Update

  • Basic Info - Carpool name, description
  • Locations - Pickup and dropoff addresses (with automatic GPS updates)
  • Schedule - Start/end dates, pickup/dropoff times, recurring days
  • Capacity - Maximum number of participants

🔒 What Cannot Be Changed

  • Carpool ID - The unique identifier remains the same
  • Creator - The original creator cannot be changed
  • Creation Date - When the carpool was first created

✅ Update Process

  1. Form Pre-fill - Current carpool data is loaded into the form
  2. Make Changes - Update any fields you want to change
  3. Smart Validation - System checks for conflicts and issues
  4. Location Updates - New addresses are automatically geocoded
  5. Save Changes - Updates are applied securely

📢 Automatic Notifications

  • Location Changes - All participants are notified of new pickup/dropoff locations
  • Schedule Changes - Time and date changes are communicated to everyone
  • Capacity Changes - Participants are informed if max capacity changes
  • Minor Updates - Name and description changes don't trigger notifications

⚠️ Smart Conflict Resolution

  • Capacity Issues - If you reduce max participants below current count, you'll be warned
  • Schedule Conflicts - System checks for conflicts with existing rides
  • Automatic Suggestions - The system suggests solutions to resolve conflicts
  • User Choice - You can choose to proceed or cancel based on the warnings
Technical Implementation:
  • API Endpoint: PATCH /rest/v1/carpools?id=eq.{carpoolId}
  • Request Body: UpdateCarpoolRequest with optional fields (all nullable)
  • Database Operations: Update carpools table, validate constraints
  • Update Logic: Only non-null fields are updated, preserving existing values
  • Validation: Field-specific validation for updated values
  • Error Handling: Comprehensive error messages for update failures

Carpool Management Workflow

Admin Functions

  • Participant Management: Add/remove participants, change roles
  • Schedule Management: Modify recurring patterns, add exceptions
  • Ride Management: View ride history, manage active rides
  • Carpool Settings: Privacy settings, notification preferences

Participant Functions

  • Join/Leave: Request to join, leave carpool
  • Preference Updates: Update availability, preferred times
  • Ride Participation: Confirm attendance for specific rides
  • Communication: View updates, receive notifications

Delete Carpool Workflow

Phase 1: Access Control & Authorization

  1. User navigates to carpool management screen
  2. System checks if user is admin of the carpool
  3. If not admin, delete option is hidden/disabled
  4. Admin users see "Delete Carpool" option

Phase 2: Delete Confirmation Dialog

  1. User taps "Delete Carpool" button
  2. System displays confirmation dialog with warning message
  3. Dialog shows: "Are you sure you want to delete this carpool? This action cannot be undone."
  4. User can choose "Delete" or "Cancel"

Phase 3: Carpool Deletion Process

  1. If user confirms deletion, system calls deleteCarpool()
  2. DELETE request is sent to /rest/v1/carpools with carpool ID parameter
  3. System validates deletion permissions
  4. Carpool record is removed from database
  5. Related data (participants, rides) may be cascaded based on database constraints

Phase 4: Post-Deletion

  1. Success confirmation is displayed
  2. User is redirected away from deleted carpool
  3. Carpool is removed from user's carpool list
  4. Participants may be notified of carpool deletion
Technical Implementation:
  • API Endpoint: DELETE /rest/v1/carpools?id=eq.{carpoolId}
  • Database Operations: Cascade deletion of related records
  • Authorization: Admin-only operation
  • Error Handling: Comprehensive error messages for deletion failures

Ride Workflows

Ride workflows cover the complete lifecycle of starting, tracking, and completing rides. These workflows ensure that both drivers and participants have a seamless experience with real-time updates and intelligent automation.

Start Ride Workflow

Phase 1: Pre-Start Validation

  1. User navigates to CarpoolScreen
  2. System checks if user has a scheduled ride for today
  3. System validates carpool status is "active"
  4. System checks if there's already an active ride for this carpool today
  5. If validation passes, "Start Ride" button becomes available

Phase 2: Permission & Location Setup

  1. Driver taps "Start Ride" button
  2. System checks location permissions
  3. If permissions not granted, system requests them
  4. System gets current GPS location
  5. Location is validated for direction calculation (temporary use only)

📍 Location Handling

  • Initial Location - Used only for determining ride direction (pickup vs dropoff)
  • Privacy-First - Current location is NOT sent to the server
  • Local Calculation - All geofence logic happens on the device
  • No Permanent Storage - Initial location is discarded after direction calculation

Phase 3: Direction Determination

The system uses intelligent geofencing to determine the optimal direction:

Geofence Logic (200m proximity threshold): • If at pickup (≤200m): Destination = dropoff • If at dropoff (≤200m): Destination = pickup • If far from both (>200m): User chooses destination • If close to both: User chooses destination Calculation Method: • Uses Haversine formula for distance calculation • Calculated locally on device (privacy-focused) • No location data sent to server

Phase 4: Ride Creation

  1. System creates ride record in database
  2. Ride status is set to "in_progress"
  3. Direction is stored in ride record
  4. Start time is recorded
  5. Ride ID is generated and returned

Phase 5: Background Service Start

  1. RideTrackingService is started as foreground service
  2. Service begins location tracking (45-second intervals)
  3. Persistent notification is displayed
  4. Wake lock is acquired to prevent battery optimization
  5. Live ETA updates begin

🔄 Ongoing Location Tracking

  • Continuous Tracking - Service tracks location every 45 seconds during the ride
  • Distance & ETA Calculation - Calculates distance and ETA to both pickup and dropoff
  • Database Logging - Stores distance/ETA data in ride_distance_logs table (permanent)
  • Privacy Protection - Current GPS coordinates are stored locally but not shared
  • Live Updates - Participants see real-time ETA updates without location sharing
Technical Implementation:
  • API Endpoint: POST /rest/v1/rides
  • Database Tables: rides, ride_distance_logs
  • Background Service: RideTrackingService with foreground notification
  • Privacy: Location calculations done locally, not sent to server

Ride Tracking Workflow

Phase 1: Continuous Location Tracking

  1. RideTrackingService runs in background
  2. GPS location is obtained every 45 seconds
  3. Distance to pickup and dropoff is calculated
  4. ETA is estimated using average speed (35 km/h)
  5. Data is logged to ride_distance_logs table

Phase 2: Live ETA Updates

  1. Service updates live ETA and distance
  2. Notification is updated with current information
  3. UI receives updates every 5 seconds
  4. Participants see real-time progress
  5. Driver sees live tracking information

Phase 3: Automatic Completion Detection

  1. System monitors distance to dropoff location
  2. When driver arrives within 50m of dropoff
  3. System waits for 2 consecutive checks (90 seconds)
  4. Ride is automatically marked as complete
  5. Background service stops

ETA Display Workflow

Phase 1: ETA Data Retrieval

  1. Participants request ETA information
  2. System calls get_user_active_ride_eta() function
  3. Function uses stored distance logs (no recalculation)
  4. Intelligent destination selection is applied
  5. ETA data is returned to participants

Phase 2: ETA Display Logic

Participant View Shows: • Distance to destination (where driver is going) • ETA to destination (estimated arrival time) • Destination address (pickup or dropoff) • Destination type (pickup/dropoff) • Carpool name Update Frequency: • Every 30-45 seconds for participants • Every 5 seconds for driver (live updates) • Real-time when app is in foreground

Phase 3: Error Handling & Fallbacks

  1. If no recent distance logs, system shows "Calculating..."
  2. If location services unavailable, shows last known ETA
  3. If network issues, cached data is displayed
  4. Error messages are user-friendly and actionable

Complete Ride Workflow

Automatic Completion

  1. System detects driver at dropoff location
  2. Automatic completion is triggered
  3. Ride status is updated to "complete"
  4. End time is recorded
  5. Background service stops

Manual Completion

  1. Driver taps "Complete Ride" button
  2. Confirmation dialog is displayed
  3. Driver confirms completion
  4. Ride status is updated to "complete"
  5. Background service stops

Post-Completion

  1. Ride history is updated
  2. Participants receive completion notification
  3. Driver can start next ride if applicable
  4. System prepares for next scheduled ride

Technical Architecture

Driver Perspective: Starting a Ride

Phase 1: Pre-Start Validation

  1. User navigates to CarpoolScreen
  2. System checks if user has a scheduled ride for today
  3. System validates carpool status is "active"
  4. System checks if there's already an active ride for this carpool today
  5. If validation passes, "Start Ride" button becomes available

Phase 2: Start Ride Dialog

When the driver taps "Start Ride", the system displays a confirmation dialog with:

  • Carpool name
  • Pickup location address
  • Dropoff location address
  • Location permission status indicator

Phase 3: Direction Determination Logic

The system uses the RideDirectionCalculator to determine the optimal direction locally on the device:

// Local calculation using Haversine formula val distanceToPickup = calculateDistance(currentLat, currentLng, pickupLat, pickupLng) val distanceToDropoff = calculateDistance(currentLat, currentLng, dropoffLat, dropoffLng) // Decision tree (calculated on device, no network calls) if (distance_to_pickup ≤ 200m) { direction = "AT_PICKUP" } else if (distance_to_dropoff ≤ 200m) { direction = "AT_DROPOFF" } else if (distance_to_pickup < distance_to_dropoff) { direction = "TO_PICKUP" } else { direction = "TO_DROPOFF" }
Note: Direction determination is calculated locally using the Haversine formula. No Supabase functions are called during this process - only the final result is sent to the database.

Phase 4: Ride Creation

System creates RideStartRequest with:

  • carpoolId: Current carpool ID
  • userGoogleId: Driver's Google ID
  • rideDate: Today's date (yyyy-MM-dd)
  • startTime: Current timestamp (ISO8601)
  • rideStatus: "in_progress"
  • rideDirection: Determined direction

Phase 5: Ride Tracking Service Activation

The RideTrackingService performs:

  • Wake lock management for battery optimization
  • Periodic location tracking (45-second intervals)
  • Automatic ride completion detection
  • Distance logging to database

Participant Perspective: Viewing Active Rides

Phase 1: Home Screen Load

  1. Participant opens HomeScreen
  2. System loads UserActiveRideEtaViewModel
  3. System calls get_user_active_ride_eta() database function

Phase 2: Database Query Logic

The database function performs:

  1. Find active ride for participant
  2. Get carpool GPS coordinates
  3. Calculate real-time distances (if participant location provided)
  4. Apply intelligent destination selection
  5. Calculate ETA based on distance
  6. Return formatted result

Phase 3: Real-time Distance Calculation

When participant location is available, the system calculates distances using the Haversine formula:

-- Distance to pickup distance_to_pickup := ROUND( 6371000 * acos( cos(radians(current_lat)) * cos(radians(pickup_lat)) * cos(radians(pickup_lng) - radians(current_lng)) + sin(radians(current_lat)) * sin(radians(pickup_lat)) ) );

Phase 4: UI Display

The system displays ActiveRideEtaCard with:

  • Header: "🚗 Active Ride" + "ETA: X min"
  • Distance: Formatted distance (miles/feet)
  • Updated: Time since last update
  • Ride info: "Ride started at HH:MM"
  • Destination: "To Pickup/Dropoff: [Address]"
  • Carpool: "Carpool: [Name]"

Technical Components

RideDirectionCalculator

Purpose: Intelligent direction determination based on GPS coordinates and proximity analysis.

Key Features:

  • Haversine distance calculations
  • Geofence-based proximity detection
  • Confidence scoring for direction decisions
  • Fallback logic for edge cases

RideTrackingService

Purpose: Background service for continuous ride tracking and data logging.

Key Features:

  • Foreground service with persistent notification
  • Wake lock management for battery optimization
  • Periodic location tracking (45-second intervals)
  • Automatic ride completion detection
  • Distance logging to database

Database Functions

get_user_active_ride_eta(): Optimized ETA calculation using stored distance logs (privacy-focused, no location sharing).

CREATE OR REPLACE FUNCTION public.get_user_active_ride_eta( user_google_id_param TEXT ) RETURNS TABLE ( ride_id TEXT, carpool_id TEXT, driver_google_id TEXT, ride_date DATE, start_time TIMESTAMP WITH TIME ZONE, distance_to_destination_m INTEGER, eta_to_destination_min INTEGER, eta_updated_at TIMESTAMP WITH TIME ZONE, destination_address TEXT, destination_type TEXT, carpool_name TEXT )

Ride Tracking Service

The RideTrackingService is a critical background service that provides robust, battery-optimization-resistant ride tracking. This service ensures continuous location tracking and ETA updates even when the app is backgrounded or the device has aggressive battery optimization settings.

Key Features:
  • Foreground service with persistent notification
  • Wake lock protection against battery optimization
  • Real-time location tracking and ETA calculations
  • Automatic ride completion detection
  • Background operation independent of app state
  • Service binding for live UI updates

Service Architecture

Foreground Service Implementation

The service runs as a foreground service with the following characteristics:

class RideTrackingService : Service() { private var wakeLock: PowerManager.WakeLock? = null private var trackingJob: Job? = null private val serviceScope = CoroutineScope(Dispatchers.IO + SupervisorJob()) // Tracking state private var activeRideId: String? = null private var activeCarpool: CarpoolResponse? = null private var liveEtaMinutes: Int? = null private var liveDistanceMeters: Int? = null }

Battery Optimization Protection

The service implements multiple layers of protection against battery optimization:

  • Wake Lock: Prevents CPU from sleeping during tracking
  • Foreground Service: Runs with persistent notification
  • START_STICKY: Automatically restarts if killed by system
  • High Priority Notification: Ensures visibility to user
  • Location Service Type: Properly declared in manifest

Service Lifecycle Management

The service lifecycle is managed through the following actions:

// Start tracking val serviceIntent = Intent(context, RideTrackingService::class.java).apply { action = RideTrackingService.ACTION_START_TRACKING putExtra(RideTrackingService.EXTRA_RIDE_ID, ride.id) putExtra(RideTrackingService.EXTRA_CARPOOL_DATA, carpool.id) } context.startForegroundService(serviceIntent) // Stop tracking val serviceIntent = Intent(context, RideTrackingService::class.java).apply { action = RideTrackingService.ACTION_STOP_TRACKING } context.startService(serviceIntent)

Service Integration

Service Binding in CarpoolScreen

The CarpoolScreen binds to the service to receive live updates:

// Service binding with proper cleanup DisposableEffect(Unit) { val intent = Intent(context, RideTrackingService::class.java) context.bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE) onDispose { if (isServiceBound) { context.unbindService(serviceConnection) } } }

Live ETA Updates

The service provides real-time ETA and distance updates to the UI:

// Real-time updates from background service LaunchedEffect(rideTrackingService, activeRideId) { while (isActive && activeRideId != null) { val service = rideTrackingService if (service != null && service.isTracking()) { liveEtaMinutes = service.getLiveEta() liveDistanceMeters = service.getLiveDistance() } delay(5000) // Update every 5 seconds } }

Background Tracking Process

Location Tracking Loop

The service runs a continuous tracking loop that:

  1. Gets current GPS location every 45 seconds
  2. Calculates distance to pickup and dropoff using Haversine formula
  3. Estimates ETA based on average speed (35 km/h)
  4. Logs distance data to database every 5 minutes
  5. Updates notification with live ETA and distance
  6. Auto-completes ride when arriving at dropoff location

Automatic Ride Completion

The service automatically completes rides when:

  • Driver arrives within 50 meters of dropoff location
  • Service has been running for at least 1 minute
  • Driver has been at dropoff location for 2 consecutive checks (90 seconds)

Notification Management

Persistent Notification

The service displays a persistent notification that shows:

  • Ride status ("Ride in Progress")
  • Live ETA to destination
  • Current distance to destination
  • Tap to return to app

Notification Channel

The service creates a high-priority notification channel for location services:

val channel = NotificationChannel( "ride_tracking_channel", "Ride Tracking", NotificationManager.IMPORTANCE_HIGH ).apply { description = "Notifications for active ride tracking" setShowBadge(false) }

Error Handling and Recovery

Network Resilience

The service handles network issues gracefully:

  • Continues tracking even when offline
  • Queues distance logs for upload when connection restored
  • Retries failed database operations
  • Logs errors but continues tracking

Location Service Resilience

The service handles location service issues:

  • Continues tracking with last known location
  • Handles permission changes gracefully
  • Recovers from location service failures
  • Provides fallback ETA calculations

Performance Considerations

Battery Usage

The service is optimized for battery efficiency:

  • 45-second tracking intervals (not continuous)
  • Wake lock only during active tracking
  • Efficient Haversine distance calculations
  • Minimal database operations

Memory Management

The service manages memory efficiently:

  • Coroutine-based architecture
  • Proper cleanup on service stop
  • Minimal state retention
  • Efficient data structures

Integration with Start Ride Flow

Service Start Integration

The service is automatically started when a ride begins:

  1. User taps "Start Ride" button
  2. System validates permissions and location
  3. Ride is created in database
  4. Service is started with ride and carpool data
  5. Service begins background tracking
  6. UI receives live updates from service

Service Stop Integration

The service is automatically stopped when a ride ends:

  1. User taps "Complete Ride" or service auto-completes
  2. Ride is marked as complete in database
  3. Service receives stop command
  4. Service releases wake lock and stops tracking
  5. Service stops foreground notification
  6. Service terminates

Status

✅ Implemented RideTrackingService is fully integrated and operational

✅ Implemented Background tracking with battery optimization protection

✅ Implemented Service binding and live UI updates

🔄 Active Development Continuous improvements to tracking accuracy and battery efficiency

Database Schema

Row Level Security is on for every table. Clients read and write as authenticated with the signed-in user's JWT; anon holds no table grant and can execute no function in public. Anything the policies cannot express goes through a SECURITY DEFINER function that re-checks the caller itself.

rides Table

CREATE TABLE IF NOT EXISTS public.rides ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), carpool_id TEXT NOT NULL REFERENCES public.carpools(id) ON DELETE CASCADE, user_google_id TEXT NOT NULL REFERENCES public.users(google_id) ON DELETE CASCADE, ride_date DATE NOT NULL, start_time TIMESTAMPTZ NOT NULL DEFAULT NOW(), end_time TIMESTAMPTZ, ride_status TEXT NOT NULL CHECK (ride_status IN ('in_progress','complete','abandoned')), ride_direction TEXT NOT NULL, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), -- Denormalised at start so an observer's card can name the driver and destination -- without a second read. driver_name TEXT, destination_address TEXT, -- Why tracking stopped, when it was not the driver ending the ride. tracking_stop_reason TEXT, tracking_resumed_at TIMESTAMPTZ, -- "Running late" is a hold that runs out: delay_until is its end, and every ETA surface -- adds only the time remaining. delay_minutes is the running total since the last clear, -- which is what the push text reads. delay_minutes INTEGER NOT NULL DEFAULT 0, delay_updated_at TIMESTAMPTZ, delay_until TIMESTAMPTZ, schedule_id UUID );

ride_distance_logs Table

CREATE TABLE IF NOT EXISTS public.ride_distance_logs ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), ride_id UUID NOT NULL REFERENCES public.rides(id) ON DELETE CASCADE, distance_to_dropoff_m INTEGER, eta_to_dropoff_min INTEGER, distance_to_pickup_m INTEGER, eta_to_pickup_min INTEGER, -- The GPS trail. ride_travelled_meters() sums these to report the distance actually -- driven, as opposed to the route the ride planned before it set off. current_lat DOUBLE PRECISION, current_lng DOUBLE PRECISION, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW() );

The first row for a ride is what tells the carpool the ride has started: the ride_log_push trigger fires "started" here rather than on the ride insert, so a ride is only announced once tracking is confirmed live. Later rows on a TO_PICKUP ride send a throttled ETA refresh, at most one per two minutes.

user_devices Table

CREATE TABLE IF NOT EXISTS public.user_devices ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), -- An auth.users id, not users.google_id: the two id spaces are different, and -- auth.identities is the only place they are joined (hence the mapping the sender uses). user_id UUID NOT NULL, push_token TEXT NOT NULL, device_type TEXT NOT NULL, transport TEXT NOT NULL DEFAULT 'fcm', app_version TEXT, push_environment TEXT, -- Set when FCM reports the token dead, or when the client revokes it at sign-out. disabled_at TIMESTAMPTZ, last_updated TIMESTAMPTZ NOT NULL DEFAULT NOW(), created_at TIMESTAMPTZ NOT NULL DEFAULT NOW() );

schedule_cover_requests and schedule_events Tables

The Harmony trust backend: who is responsible for a scheduled drive, who covered it, and what actually happened. Applied to dev on 2026-09-11; no client calls its RPCs yet, so these are documented as the contract rather than as shipped behaviour.

CREATE TABLE IF NOT EXISTS public.schedule_cover_requests ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), schedule_id UUID NOT NULL, requested_by TEXT NOT NULL, -- Optimistic concurrency: every responsibility RPC takes the version it expects, -- so two people racing to accept produce one outcome and one refusal. assignment_version INTEGER NOT NULL, status TEXT NOT NULL, note TEXT, accepted_by TEXT, requested_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), resolved_at TIMESTAMPTZ ); CREATE TABLE IF NOT EXISTS public.schedule_events ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), schedule_id UUID NOT NULL, actor_google_id TEXT NOT NULL, event_type TEXT NOT NULL, assignment_version INTEGER NOT NULL, from_driver_google_id TEXT, to_driver_google_id TEXT, ride_id UUID, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW() );

API Reference

Start Ride

POST /rest/v1/rides

Request Body:

{ "carpool_id": "string", "user_google_id": "string", "ride_date": "string", "start_time": "string", "ride_status": "in_progress", "ride_direction": "string" }

Get User Active Ride ETA

Function Call: get_user_active_ride_eta

Parameters:

  • user_google_id_param (string, required): the caller's Google ID. Their own rides are excluded — this answers "who is driving me", not "am I driving".
  • carpool_id_param (string, optional): narrows the answer to one carpool.

Returns one row: ride_id, carpool_id, driver_google_id, driver_name, ride_date, start_time, distance_to_destination_m, eta_to_destination_min, eta_updated_at, destination_address, destination_type, carpool_name.

The leg is chosen by the ride's ride_direction, never by whichever distance happens to be present, and the ETA carries whatever is left of a declared delay hold. eta_updated_at is the observation time: clients anchor the arrival clock to it rather than recomputing from "now", and show the data's age.

Remote procedures

Everything a policy cannot express goes through a function that re-checks the caller. All are executable by authenticated only.

FunctionWhat it is for
preview_carpool(code)Join-code lookup before joining. Returns name, days, times and seats taken — deliberately no addresses or coordinates, since the 6-character code is the only secret.
join_carpool_by_code(code, persona, priority_days, notes)Joins the caller, taking the identity from the JWT so a client cannot disagree with its own token. Idempotent.
generate_smart_schedule(carpool_id)Rebuilds a carpool's rota. Membership is checked in front of the algorithm.
report_ride_delay(ride_id, minutes)Extends the driver's "running late" hold; returns the minutes of hold remaining. Driver only, capped at three hours.
clear_ride_delay(ride_id)"Back on time" — ends the hold early. Driver only.
ride_travelled_meters(ride_ids[])Sums each ride's GPS trail, so history reports distance driven rather than distance planned. Membership-scoped.
get_user_trip_statistics(user_google_id_param)Totals for the profile screen.
upsert_push_token(token, transport, app_version, environment)Registers this device against the signed-in user.
disable_push_token(token)Revokes this device's token at sign-out, while the JWT still identifies its owner.
request_schedule_cover, accept_schedule_cover, cancel_schedule_cover, cancel_schedule_occurrence, admin_reassign_schedule, report_schedule_outcome, correct_schedule_outcomeHarmony trust responsibility and cover. Each takes the assignment_version it expects, so concurrent acceptance resolves to one outcome. Applied to dev; no client calls them yet.

Push notifications

Data-only FCM messages through the notify-ride-started edge function, fired by database triggers. A notification block would be rendered by the system while the app is backgrounded, which would lose both update-in-place ETAs and cancel-on-ride-end.

  • kind=started — the ride's first GPS log landed, carrying the first ETA.
  • kind=eta — throttled refresh for TO_PICKUP rides, at most one per two minutes; updates the existing notification silently and never re-posts a dismissed one.
  • kind=delay — the driver declared themselves late; allowed to alert.
  • kind=ended — arrived, or ended before arriving. An abandoned ride is not called a cancellation, because the stale-ride sweeper abandons rides too.

Every message carries recipient_user_id, which the receiver checks against the signed-in session before displaying anything, so a delayed push cannot surface one account's ride on another's phone. Transient send failures are retried twice; a 2xx is acceptance by FCM, not delivery to a phone.

Data Models

Ride

interface Ride { id?: string; carpool_id: string; user_google_id: string; ride_date: string; // YYYY-MM-DD start_time: string; // ISO8601 end_time?: string; // ISO8601 ride_status: 'in_progress' | 'complete' | 'abandoned'; ride_direction?: 'TO_PICKUP' | 'TO_DROPOFF' | 'AT_PICKUP' | 'AT_DROPOFF' | 'UNKNOWN'; created_at?: string; // ISO8601 }

Enhanced Error Handling System

The Karpool app implements a comprehensive error handling system that provides user-friendly error messages, network awareness, and smart retry mechanisms across all screens. This system ensures a consistent and professional user experience even when things go wrong.

Key Features:
  • User-friendly error messages with contextual help
  • Real-time network connectivity monitoring
  • Smart retry mechanisms with exponential backoff
  • Consistent error handling patterns across all screens
  • Network-aware loading states and offline indicators

Error Handling Architecture

Core Components

AppError Sealed Class

The foundation of the error handling system is the AppError sealed class that categorizes different types of errors:

sealed class AppError { // Network Issues data class NetworkError(val message: String) : AppError() data class TimeoutError(val message: String) : AppError() data class OfflineError(val message: String) : AppError() // Server Issues data class ServerError(val statusCode: Int, val message: String) : AppError() data class ServiceUnavailableError(val message: String) : AppError() // Authentication Issues data class AuthenticationError(val message: String) : AppError() data class AuthorizationError(val message: String) : AppError() // Data Issues data class ValidationError(val message: String) : AppError() data class NotFoundError(val message: String) : AppError() // Unknown Issues data class UnknownError(val message: String) : AppError() }

AppResult Custom Result Type

A custom AppResult<T> type provides structured error handling with success/failure states and helper methods for error processing.

NetworkStatusManager

Real-time network connectivity monitoring that provides:

  • Current online/offline status
  • Connection type detection (WiFi, Mobile, Ethernet)
  • Network quality assessment
  • Flow-based network status updates

RetryManager

Smart retry logic with exponential backoff that:

  • Automatically retries failed operations
  • Uses exponential backoff with jitter
  • Respects error type retryability
  • Configurable retry strategies

Enhanced UI Components

ErrorCard Component

User-friendly error display with:

  • Contextual error messages with emojis and clear explanations
  • Color-coded error types (orange for network, red for server, etc.)
  • Smart retry buttons for recoverable errors
  • Dismiss functionality for non-critical errors
// Example error messages: "🌐 No Internet Connection - Please check your internet connection and try again." "⏱️ Connection Timeout - Our servers are taking longer than usual to respond." "🔧 Server Maintenance - Our servers are temporarily unavailable." "🔐 Authentication Failed - Please sign in again to continue."

LoadingWithNetworkStatus Component

Network-aware loading indicators that show:

  • Loading progress with network quality indicators
  • Connection type (WiFi, Mobile, Offline)
  • Contextual loading messages

OfflineIndicator Component

Global offline status indicator that appears when the user is offline, providing clear feedback about connectivity issues.

Screen Integration

The enhanced error handling system is integrated across all screens:

MainActivity

  • Global network monitoring
  • Global offline indicator
  • Network status flow management

HomeScreen

  • Enhanced carpool loading errors
  • Authentication error handling
  • Network-aware loading states

CarpoolScreen

  • Enhanced carpool loading errors
  • Network status integration
  • Smart error recovery

CreateCarpoolScreen

  • Enhanced carpool creation errors
  • Network-aware loading states
  • Smart retry mechanisms

ManageCarpoolScreen

  • Enhanced carpool management errors
  • Network status integration
  • Smart error recovery

ParticipantCarpoolScreen

  • Enhanced participant operation errors
  • Network status integration
  • Smart error recovery

LoginScreen

  • Enhanced authentication errors
  • Network-aware loading states
  • Smart retry mechanisms

PermissionRequestScreen

  • Network status awareness
  • Enhanced offline handling
  • Smart error recovery

User Experience Benefits

Before Enhanced Error Handling:
  • ❌ Generic error messages: "Error: java.net.SocketTimeoutException"
  • ❌ No network awareness
  • ❌ No retry mechanisms
  • ❌ Technical error details exposed to users
  • ❌ Inconsistent error handling across screens
After Enhanced Error Handling:
  • ✅ User-friendly messages with clear explanations
  • ✅ Network awareness with real-time connectivity monitoring
  • ✅ Smart retry buttons for recoverable errors
  • ✅ Contextual help based on error type
  • ✅ Global offline indicator across the entire app
  • ✅ Consistent UX with the same error handling patterns

Technical Implementation

Error Flow

  1. Operation fails with technical error
  2. Error is caught and categorized into appropriate AppError type
  3. User-friendly message is generated using getUserFriendlyMessage()
  4. Error card is displayed with appropriate styling and actions
  5. User can retry (if applicable) or dismiss the error

Network Monitoring

  1. NetworkStatusManager monitors connectivity changes
  2. Network status flow updates all subscribed components
  3. UI components show appropriate network indicators
  4. Offline operations are handled gracefully

Retry Logic

  1. Failed operation is analyzed for retryability
  2. If retryable, RetryManager applies exponential backoff
  3. Operation is retried with increasing delays
  4. Final error is displayed if all retries fail

Status

✅ Implemented Core functionality is complete and operational

✅ Implemented Enhanced error handling system across all screens

🔄 Active Development Continuous improvements to geofence accuracy

📋 Planned Enhanced notifications and route optimization

Note: This documentation is actively maintained and updated with each release. For the most up-to-date information, refer to the source code and database schema.

Version History

Versions below 1.0 are the real app versions, from version.properties (versionName / versionCode), which every debug build increments. The 2.x entries further down are an older documentation-only numbering and do not correspond to any shipped build.

0.1.79-alpha (versionCode 53) - September 12, 2026

The tracking sprint. Eighteen findings from a source audit of the Android ride flow, plus two faults found on the first real test drives.

  • Arrival needs evidence. A ride used to complete the instant a fix landed within 300 m, which ended rides that started near the destination or merely drove past. Arrival is now a visit: slow time inside 300 m accumulates, a brief move pauses it rather than resetting it, and a stop followed by the car getting 500 m away completes the ride too. The ride is dated to when the car arrived. Shared by Android and iOS.
  • Distance cannot read closer than the straight line. The countdown subtracted distance travelled in any direction, so observers saw "30 m" while the car was 590 m away and "0 m" while it drove off.
  • Start and end tell the truth. Permission and location-service checks before starting, visible errors and retry, end by explicit ride id awaiting a persisted or queued result, and a tear-down that no longer leaves a finished ride to be resumed on the next cold start.
  • "Running late" is a hold that runs out, with "Back on time", restored after a relaunch, and consistent across driver, home, observer screen and notification.
  • Notifications: a ride announces itself only once tracking is live, ETA refreshes reach the phone through Doze, an ended ride says whether it arrived, late events cannot revive a finished ride, sign-out revokes the device token, and every message names its intended recipient.
  • Observer surfaces: honest data age and stale states, one live ride per carpool, Become a driver, Leave, and per-carpool mute.
  • iOS gained the same arrival rule, running late, and the observer fixes. It still has no APNs transport.

Database: RLS on every table, anon holds no function grant, the delay hold, the lifecycle push triggers, and the Harmony trust schema (applied, unused).

Version 2.1.8 - September 21, 2025

Documentation Accuracy - Code-Based Implementation Details:
  • Problem: Documentation didn't reflect actual code implementation
  • Solution: Analyzed actual carpool create/update/delete code and updated documentation
  • Validation Rules: Documented actual validation logic from ViewModels and Repositories
  • API Endpoints: Corrected endpoint formats and request/response structures
  • Granular Address System: Documented comprehensive address component system
  • Delete Workflow: Added missing carpool deletion workflow documentation

Documentation Accuracy Improvements

  • Updated validation rules to match actual code implementation
  • Corrected API endpoint formats (POST/PATCH/DELETE /rest/v1/carpools)
  • Documented granular address component system (street, city, state, postal code)
  • Added carpool deletion workflow with confirmation dialog
  • Updated technical implementation details with actual database operations
  • Corrected field requirements and validation logic

Version 2.1.6 - January 16, 2025

Latest Updates:
  • ETA Function Field Cleanup: Removed redundant fields for better performance
  • Response Optimization: Reduced payload size by removing unnecessary data
  • Participant Focus: Function returns only data relevant to participants
  • Performance Improvement: Smaller response size and faster data transfer
  • Documentation Standards: Cursor rules for consistent changelog and summary practices

ETA Function Field Cleanup

  • Removed redundant fields: current_distance_to_pickup_m, current_distance_to_dropoff_m
  • Returns only essential participant data
  • Reduced response payload size
  • Faster data transfer and processing
  • Function signature: get_user_active_ride_eta(user_google_id_param TEXT)

Version 2.1.0 - January 16, 2025

Major Updates:
  • RideTrackingService Integration: Complete integration of background ride tracking service
  • Enhanced Error Handling: Comprehensive error handling system across all screens
  • Battery Optimization Protection: Foreground service with wake lock and persistent notification
  • Real-time Updates: Live ETA and distance updates from background service to UI
  • Service Binding: Proper service lifecycle management in CarpoolScreen

RideTrackingService Features

  • Foreground service with persistent notification
  • Wake lock protection against battery optimization
  • 45-second location tracking intervals
  • Automatic ride completion detection
  • Background operation independent of app state
  • Service binding for live UI updates
  • Network and location service resilience

Enhanced Error Handling

  • AppError sealed class for structured error handling
  • AppResult custom result type
  • NetworkStatusManager for real-time connectivity monitoring
  • RetryManager with exponential backoff
  • Enhanced UI components (ErrorCard, LoadingWithNetworkStatus, OfflineIndicator)
  • Integration across all screens (MainActivity, HomeScreen, CarpoolScreen, etc.)

Version 2.0.0 - January 15, 2025

Core Features:
  • Start Ride Flow: Complete ride initiation and tracking system
  • Real-time Geofence: Live location-based destination selection
  • Intelligent Direction Detection: Automatic pickup/dropoff determination
  • User Choice Dialog: Manual destination selection when ambiguous
  • Permission System: Comprehensive permission management

Start Ride Features

  • Permission request flow with proper ordering
  • Location-based direction calculation
  • User choice dialog for ambiguous locations
  • Real-time ETA calculations
  • Automatic ride completion

Database Functions

  • get_user_active_ride_eta() with real-time geofence calculations
  • Haversine distance calculations in SQL
  • Intelligent destination selection logic
  • Ride status constraints (in_progress, complete, abandoned)

Version 1.0.0 - January 14, 2025

Initial Release:
  • Core Carpool System: Basic carpool creation and management
  • User Authentication: Google Sign-In integration
  • Database Schema: Complete carpool and user management tables
  • Basic UI: Material 3 design with dark theme

Core Features

  • Carpool creation and management
  • User authentication with Google
  • Participant management
  • Schedule management
  • Basic ride tracking (without background service)
Documentation Maintenance:
This documentation is updated with each major release. Version numbers follow semantic versioning (MAJOR.MINOR.PATCH).
Last Updated: January 16, 2025
Next Review: February 1, 2025