Socket.io powers two real-time modules in CruciDrive: sector-based GPS location broadcasting and in-ride chat messaging. Every feature that updates without a page refresh — a driver’s pin moving on the map, a chat bubble appearing — is delivered over a single persistent Socket.io connection that both the passenger and driver apps share. All connections must authenticate with a valid Supabase JWT before the server permits any events.Documentation Index
Fetch the complete documentation index at: https://mintlify.com/DavidCevallos15/Crucidrive---APP/llms.txt
Use this file to discover all available pages before exploring further.
Connecting
TheuseSocket hook in frontend/src/hooks/useSocket.ts manages the lifecycle of the connection. It reads the Supabase session from the useAuthStore and creates a new socket whenever an access_token is present, disconnecting automatically when the session expires.
The socket URL is read from the
EXPO_PUBLIC_SOCKET_URL environment variable
via the SOCKET_CONFIG.url constant in frontend/src/constants/config.ts.
In local development this defaults to http://localhost:3000. Set
EXPO_PUBLIC_SOCKET_URL in your .env file to point at the production
backend before building a release.Authentication flow
Before any client can emit or receive events, the server runs anio.use() middleware that validates the Supabase JWT. The steps are:
- Token extraction — the middleware reads
socket.handshake.auth.token. If that value is absent it falls back to theAuthorizationheader (Bearer <token>format). - JWT verification —
supabase.auth.getUser(token)is called. Supabase validates the token signature and expiry server-side. - Profile hydration — the middleware queries
public.perfilesfor the authenticated user’srolandnombre, then attaches the full identity object to the socket:
- Failure path — if the token is missing, invalid, or expired, the server calls
next(new Error(...)). Socket.io translates this into aconnect_errorevent on the client and immediately closes the handshake. No events are reachable until a valid token is supplied.
Connection events
Register these listeners immediately after creating the socket to monitor connection health:| Event | Direction | When it fires |
|---|---|---|
connect | server → client | Handshake succeeded; socket.id is assigned |
disconnect | server → client | Connection closed for any reason; reason string describes the cause |
connect_error | server → client | Handshake failed — bad token, server down, or network error |
error_message | server → client | A specific event was rejected by server-side business logic |
Room architecture
CruciDrive uses two families of Socket.io rooms to target messages precisely, avoiding broadcast storms that would drain data budgets on mobile:sector:{sectorId} — GPS sector rooms
Clients call join_sector to subscribe to driver location updates for a named zone in Crucita. The available sectors match the geographic divisions of the town:
sector:playasector:centrosector:las_gilcessector:los_arenalessector:san_jacinto
update_location, the server writes the new position to tricimotos.ubicacion_actual and then calls socket.to('sector:{sectorId}').emit('location_updated', ...) — only passengers in that sector room receive the update.
chat:{threadId} — ride-specific private chat rooms
When a ride is accepted, a thread is created and both the passenger and driver are added to thread_members. Each party calls join_chat to enter the room chat:{threadId}. Messages sent via send_message are broadcast to the entire room with io.to(room).emit(...), which includes the sender — so both parties always see the same message state without any client-side deduplication logic.
Using rooms means a passenger in sector:playa never receives GPS pings from sector:centro, and a user in one chat thread never sees messages from another ride. This targeted delivery keeps per-device data consumption well within the 15 MB per-shift budget enforced by the app.
Reconnection behavior
TheSOCKET_CONFIG constants configure automatic reconnection:
| Parameter | Value | Meaning |
|---|---|---|
reconnection | true | Automatically attempt to reconnect on drop |
reconnectionAttempts | 5 | Give up after 5 consecutive failed attempts |
reconnectionDelay | 2000 ms | Wait 2 seconds between each attempt |
connectionTimeout | 10000 ms | Fail the initial handshake after 10 seconds |
socket.id and is no longer in any rooms. Your components must re-emit join_sector and join_chat to restore subscriptions — the server has no memory of previous room membership for a given connection.