Ride Schema

Firestore Document (rides/{rideId})

Field Type Required Constraints Description
id string yes non-empty Unique ride identifier (nanoId)
creatorId string yes non-empty UID of the ride creator; also the first admin
adminIds string[] yes non-empty array UIDs of ride admins; always includes creatorId
groupId string \| null no Group UID if this ride belongs to a group; null for standalone rides
type "private" \| "public" yes enum Discovery scope: private = link-only, public = app-wide
title string yes non-empty Display name of the ride
description string no Optional long-form description
startAt Timestamp yes must be before endAt Scheduled ride start time
endAt Timestamp yes must be after startAt Scheduled ride end time
posterUrl string \| null no valid URL Cover image URL; may be sourced from Google Places photo for the destination
settings.requireRsvpApproval boolean yes If true, RSVPs require creator/admin approval before access is granted
settings.maxRiders number yes integer ≥ 0 Max yes-status participants; 0 means unlimited
startLocation.id string yes non-empty Unique waypoint identifier
startLocation.placeId string \| null no Google Places API place ID
startLocation.latitude number yes −90 to 90 WGS-84 latitude
startLocation.longitude number yes −180 to 180 WGS-84 longitude
startLocation.title string yes non-empty Human-readable location name
startLocation.type "origin" yes fixed value Always "origin"
endLocation.id string yes non-empty Unique waypoint identifier
endLocation.placeId string \| null no Google Places API place ID
endLocation.latitude number yes −90 to 90 WGS-84 latitude
endLocation.longitude number yes −180 to 180 WGS-84 longitude
endLocation.title string yes non-empty Human-readable location name
endLocation.type "destination" yes fixed value Always "destination"
breakpointsTo Location[] no max 6 items (8 total incl. origin + destination) Intermediate waypoints; see Location type below
createdAt Timestamp yes server-set Document creation time
updatedAt Timestamp yes server-set Last modification time

Location object (used in breakpointsTo):

Field Type Required Constraints Description
id string yes non-empty Unique waypoint identifier
placeId string \| null no Google Places API place ID
latitude number yes −90 to 90 WGS-84 latitude
longitude number yes −180 to 180 WGS-84 longitude
title string yes non-empty Human-readable location name
type string yes enum One of additionalDestination, meetingPoint, haltPoint, restaurant, fuelStation, other
{
  "id": "abc123",
  "creatorId": "uid_creator",
  "adminIds": ["uid_creator"],
  "groupId": null, // or "gid_xyz" for group rides
  "type": "public", // "private" | "public"
  "title": "Weekend Ghat Run",
  "description": "Scenic route through the Western Ghats",
  "startAt": "2025-06-01T06:00:00Z", // Firestore Timestamp
  "endAt": "2025-06-01T14:00:00Z", // Firestore Timestamp
  "posterUrl": "https://example.com/poster.jpg", // optional
  "settings": {
    "requireRsvpApproval": false,
    "maxRiders": 25, // 0 = unlimited
  },
  "startLocation": {
    "id": "loc_start",
    "placeId": "ChIJ...", // optional Google Places ID
    "latitude": 12.9716,
    "longitude": 77.5946,
    "title": "Bangalore City Center",
    "type": "origin",
  },
  "endLocation": {
    "id": "loc_end",
    "placeId": "ChIJ...", // optional
    "latitude": 15.3647,
    "longitude": 75.1240,
    "title": "Hampi",
    "type": "destination",
  },
  "breakpointsTo": [
    {
      "id": "loc_bp1",
      "placeId": null,
      "latitude": 13.9299,
      "longitude": 75.5681,
      "title": "Chitradurga Fort",
      "type": "haltPoint",
    },
  ],
  "createdAt": "2025-05-01T10:00:00Z", // Firestore Timestamp
  "updatedAt": "2025-05-01T10:00:00Z", // Firestore Timestamp
}

Sub-collections

rides/{rideId}/participants/{userId}

Field Type Required Constraints Description
id string yes non-empty UID of the participant (matches document ID)
name string yes non-empty Display name of the rider
photoUrl string yes valid URL Avatar URL
joiningLocationId string yes (if status is yes or maybe) must match a location id in the ride ID of the breakpoint where the rider joins
status "yes" \| "no" \| "maybe" yes enum RSVP status; maybe auto-upgrades to yes when ride starts
{
  "id": "uid_rider",
  "name": "Arjun Mehta",
  "photoUrl": "https://example.com/avatar.jpg",
  "joiningLocationId": "loc_start", // must match a location id on the ride
  "status": "yes", // "yes" | "no" | "maybe"
}

rides/{rideId}/routes/{routeId}

routeId encodes direction and alternative index: to-0 is the first outgoing route (origin → destination), to-1 the second alternative, from-0 the first return route (destination → origin).

Currently only to-0 is stored. Return routes and multiple alternatives are planned.

Refer to the Route Schema for the full route document structure.

Server-Controlled Fields

The following fields are set exclusively by the server. They are never accepted in any API request body. The RideRequestSchema (used by Create and Update endpoints) must omit all of them.

Field Set by
id Server on create (nanoId)
creatorId Server on create (authenticated user's UID)
adminIds Server on create; modified only via Manage Admins
status Server on state transitions (publish, cancel, delete)
deletedAt Server on delete
createdAt Server on create
updatedAt Server on every write

Security invariant: Accepting status or deletedAt in a client request allows any ride admin (not just the creator) to delete or corrupt ride state via the Update endpoint. The Create and Update handlers must strip these fields before writing to Firestore.

Indexes

Fields Query Type Reason
creatorId asc Single-field Fetch all rides created by a user
groupId asc + startAt asc Composite Group ride feed ordered by start time
type asc + startAt asc Composite Public ride discovery ordered by start time
creatorId asc + startAt desc Composite User's ride history in reverse-chronological order