Change list and test notes

Back to the app launcher

Add only, remove nothing. No existing function, screen, field or Firebase configuration was deleted. The three files you supplied are kept byte for byte as the backup masters under /original/. The working copies are the ones the launcher opens, and every change in them is either a new file, a new function, a wrapper around an existing function (the original stays reachable on window.originalRiderFirebase and window.originalDriverFirebase), or an added column, field or section.

Firebase layout, as found

ProjectUsed byHolds
driver-pro-card-loginRider app, Admin app, and now the Driver app for ride data trips, active_trip_request, pricing, reservations, riders, lost_and_found, support_chats, plus the mirrored drivers and new driver_locations
rider-s-drivers-infoDriver app login and approval drivers/{uid} with the full application, documents and bank details

The Driver app also loads the Firebase compat SDK for its wallet screen, pointed at driver-pro-card-login. That was left exactly as it was.

Root cause

The Rider app writes a request to active_trip_request and trips/{id} in driver-pro-card-login. The Driver app was listening to active_trip_request in rider-s-drivers-info. Two different projects, so the request never arrived, no driver was ever assigned, and Admin only ever saw an unassigned request. Everything else downstream (chat, GPS, payment, ratings) failed for the same reason.

Rider app

Driver app

Admin app

Shared layer and tests

Hardening after the code review

A second pass over the bridges found races that only show up when two people act at the same moment. All of these are fixed and covered by tests:

Second review pass: five defects fixed

Real time driver location on the rider map

The Driver app's device GPS was already working and already publishing. The Rider app was reading the wrong copy of it.

What the Driver app does (unchanged): navigator.geolocation.watchPosition with high accuracy, started when the driver goes online and when a ride is accepted, stopped when the driver goes offline with no ride, logs out or is locked. Every fix writes to four places:

The mismatch: the Rider app only ever read the last of those, the throttled copy carried on the trip record. So the car could move at best once every three seconds, only when the whole trip record changed, and it froze completely if that one write was skipped. The live per driver feed that the Driver app was already publishing was not being read by anyone except the Admin dashboard.

The fix: the Rider app now subscribes to driver_locations/{driverId} for the driver assigned to its own trip, so the car moves as the driver moves. Details:

Rider payment information

The payment data was always being written. Nothing in the Rider app ever displayed it: the rider only saw the fare estimate before the ride and the tip window at the end. Traced end to end, the money for a ride lives in one place, trips/{tripId} in the canonical project, mirrored on active_trip_request while the ride runs:

FieldWritten byWhen
fare, estimatedFareRiderwhen the ride is requested
paymentMethodRiderrequest, and whenever the selector changes
paymentStatusRider, DriverPENDING, AUTHORIZED on accept, CHARGED or CASH_DUE on completion, PAID at the end
tipAmount, driverPayoutRiderwhen a tip is added
finalFareDriveron completion, fare plus tip
paymentUpdatedAtRider, Driverevery payment change
paymentReference (new)systemissued once per trip on completion, derived from the tripId
paymentAttempts, paymentFailureReason, lastPaymentAttemptAt (new)systemonly when a payment fails and is retried

What was added, all reading that same record:

Road distance and road time, from the routers already in the project

Two road routing services were already configured here, and both are now used for what they are good at. Nothing new was added, no API key, nothing paid.

The rider quote is now priced only from a road route. Straight line distance and average speed guesses are not used for it at all. If neither router answers, the ride is not created and the rider is told to check the addresses: better than the old behaviour, which quietly used 5 miles, 10 minutes and $18.50.

The driver's pickup distance and ETA are now real. The request card used to read "~5 mins (1.8 miles)" because nothing ever wrote pickupDistance or pickupEta. The road route is worked out from the driver's current GPS to the rider's pickup, shown on the request card, refreshed as the driver gets closer, and saved to the trip once the driver owns it so the rider and Admin see the same numbers.

Estimated and actual stay apart on the one trip record: estimatedRoadMiles and estimatedRoadMinutes from the road route before the ride, actualTripMiles and actualTripMinutes from the driver's GPS and the clock afterwards, alongside the existing fields. The fare formula was not touched.

Upfront pricing, quoted from the road route

What was wrong with the fare. The request carried miles: document.getElementById('miles').value || 5, minutes: ... || 10 and a fare of "$18.50" whenever the fare box still showed $0.00. So any ride where the route lookup did not answer, which is every ride if the map key is restricted or billing is off, was quoted at $18.50 for 5 miles and 10 minutes, whatever the real trip was.

What it does now. The rider is quoted before the ride from the expected ROAD ROUTE, using the pricing table Admin already controls. No second pricing system: the arithmetic is the one the Rider app has always used, base plus distance plus time, floored at the minimum, plus the booking fee, times the period multiplier, with an airport flat rate replacing all of it.

For the reported trip, Riviera Beach to Fort Lauderdale airport with no route service answering, the quote is $74.26 for an estimated 60.97 miles and 73 minutes, against the old $18.50.

Why a 57 mile drive still read 4.2 miles

The first version of the odometer only ran between Start Trip and Complete Trip. Two things followed from that, and both produced the old placeholder numbers:

Tracking now runs for the whole time the driver owns the ride, from the moment they accept. The single track is marked at arrival and at Start Trip, so it splits into the drive to the rider and the ride itself without a second GPS system. The ride is measured from Start Trip when it is pressed, and from the arrival when it is not, so a forgetful driver still produces a real distance. If startedAt is missing at completion it is filled in from the arrival time and the record says startedAtEstimated, so the duration is real rather than zero.

The trip card is also refreshed every second from the live measurement, in every stage of the ride, so the app's own placeholders can never be what the driver reads.

Measured, not displayed. The engine is checked against the reported trip: Riviera Beach to Fort Lauderdale airport, a road route of 57.45 miles where the straight line between the two addresses is 48.78. Fed a realistic GPS trace of that drive, the odometer reports 57.45 miles, an error of 0.00%. A ten mile leg reports ten miles. Nothing was hard coded to display 57: the same code measures whatever is driven.

Real mileage and real trip time

What was wrong. Nothing in any of the apps ever measured how far a car drove. The driver screen read activeTrip.tripMiles || "4.2 mi" and activeTrip.tripDuration || "12 mins", and nothing anywhere wrote tripMiles or tripDuration. So every trip displayed those two constants. The only distance in the system was the route estimate the rider's map produced before the ride, which is not the distance driven, and no duration was calculated at all.

Mileage. While a ride is in progress the driver app now accumulates real distance between consecutive GPS fixes using the haversine formula, on the same fixes the live map already publishes. No second GPS system was created. Bad data is filtered: movements under 6 m are jitter, fixes accurate to worse than 100 m are not measured with, and anything implying more than about 139 mph is rejected. A long gap counts the straight line rather than losing the distance. Two impossible steps in a row re-anchor the odometer, so one bad fix, or a stale position left over from before the ride, cannot wedge it at zero for the whole trip.

Time. startedAt is stamped when the driver presses Start Trip and completedAt when they end it, and the duration is completedAt - startedAt. GPS frequency cannot shorten it: a twenty minute ride reads twenty minutes even if only three fixes arrived.

Both are saved to the canonical trips/{tripId} record as distanceMeters, tripMiles, tripMilesValue, tripDurationSeconds, tripDurationMinutes and tripDuration, with the GPS fix counts kept for auditing. The driver sees them live on the trip card and again on the completion summary, the rider sees them on the payment card, and Admin shows them on the live ride and in each rider's trip table.

Double clicking the wrong file

The package contains two files that both look like the Admin app. Only one of them can be opened by double clicking, and the other one failed silently, which is indistinguishable from a broken login.

Telling you why a login failed

The Admin login card has a Run connection test button. It reports the build that is loaded, whether the page was opened as a local file or over http, whether the shared code loaded, whether the email is on the admin list, whether each Firebase project can actually be reached, what the last sign in attempt returned from each project, and whether the browser thinks it is online. One press answers "why can I not log in" without another round trip.

Running Admin on your own computer

Copying admin.html to a computer and opening it did not work, for two reasons.

So there is now a download page with two forms of the same working app: admin-standalone.html, one file that opens by double click because the shared code is inlined and no local import remains, and riders-admin-package.zip, the normal layout with the shared folder and a one command local server. The Firebase configuration, both projects, the login and every feature are the working code, copied as is.

No cash on the rider screen, even on an old trip

Trips taken before the card only change still carry paymentMethod: "Cash" in the database, and the Rider app was faithfully printing it. A rider should not be shown a payment type they can no longer use, so:

Card only, and the driver never handles money

Riders pay by credit or debit card. Cash is gone from the Rider app, and the driver is never asked to collect anything.

Rider app

Driver app

Trip record

driverEarnings now sits next to driverPayout, carrying the same number under the name the dashboards ask for. Payment state still only moves forward, and a card trip that has been charged or paid can never fall back to a cash state, even from a stale mirror. Older cash trips still read and settle exactly as they always did: history is not rewritten.

The stuck ride, the wrong payment status and the zero total

Three symptoms, three separate causes, none of them a Firebase project mismatch. Rider, Driver and Admin all read the ride data from driver-pro-card-login, and Admin additionally reads registrations from rider-s-drivers-info. That part was correct.

"Another ride is active right now"

active_trip_request is a single shared node. If a tab closes mid ride, or a ride is finished only in the trip record, the pointer is left aiming at a ride that is over, and then nobody can book. Forever. The stored trip is the authority now: a pointer to a finished ride is released, and a request with no driver that has been sitting for more than half an hour is treated as abandoned, marked cancelled in history and released. A genuine ride in progress still blocks, and the rider is told which ride, what state it is in, which driver has it and how long it has been running.

Admin said PENDING while the Rider app said AUTHORIZED

Both were reading the correct field on the correct record. They were reading different rides: Admin quoted the newest trip by timestamp, the Rider app showed the ride that device was on. Admin now quotes the ride that is happening now when there is one, names the trip id beside the status, and marks it as a live ride. With nothing running it falls back to the newest finished ride, as before.

Trips: 2 / $0.00

The riders table showed only money that had settled, and neither of that rider's rides had completed. It now reads "2 rides, $50.90 in fares" with the settled amount beneath, so a fare is never invisible just because the ride has not closed out yet.

Payment Method: Not specified

That rider record carries no card because it is the record the Rider app creates on the device, not the registration record that holds the card. Where the account has no card but the rider's rides do, Admin now shows the method used on the ride and says plainly that it came from a ride rather than from the account.

Fares in the Rider Information view

The payment summary only added up rides that had finished, so a rider with two rides still running read $0.00 for everything and looked as though the fare was missing. It now separates what is settled from what is not:

In the trip table inside the view, a ride that has not finished now shows its fare marked "not settled" instead of a bare $0.00 in the Final Fare column.

Who and how much, in both trip tables

Live Active Rides & Trip Requests and Ride Request & Trip History now carry, for every ride: the rider name with the rider id underneath, the driver name with the driver id (and plate) underneath, and the fare split into three columns.

A $32.40 fare reads $12.96 to the driver and $19.44 to the company, and the two always add back to the fare. Tips sit on top and go entirely to the driver, so they never reduce the company share. These are the same numbers the Driver app pays out and the dashboard totals already used, now from one shared calculation rather than three copies of the arithmetic.

Payment method on the rider record, ready for Stripe

The registration page always wrote safe card metadata, and it never wrote a card number, a security code or an expiry date. Those stay in the form and are thrown away. What was missing was one agreed shape, so the rider record now carries:

riders/{uid}
  savedCard             "Visa \u2022\u2022\u2022\u2022 4242"
  paymentMethodType     "card"
  paymentMethodLabel    "Credit/Debit Card"
  paymentMethodStatus   "pending"  (no provider yet)  or  "ready"  (Stripe holds it)
  paymentMethodId       ""  or  "pm_..."
  paymentMethodAddedAt  timestamp
  cardBrand, cardLast4  kept, nothing was removed

Admin reads that shape whatever wrote the record, shows the Stripe id and marks a Stripe backed method as ready. When a rider row has no card at all it now says which fields it looked for and which source the row came from, instead of leaving "None saved at registration" hanging.

How Stripe drops in

shared/stripe-config.v1.js holds one value, the publishable key. Paste it there and the registration page loads Stripe.js, mounts Stripe's own card field, hides its own card inputs (they stay in the page), and turns the card into a PaymentMethod. The card is typed into an iframe served by Stripe and never touches this site. Firebase then stores only the brand, the last four, the pm_ id and a status.

Leave the key empty and nothing changes: the current form keeps working and keeps storing only brand and last four.

The secret key never goes in this repository. Creating a PaymentMethod needs only the publishable key. Charging it, refunding and paying drivers need the secret key and must run on a server. The trip record is already shaped for that: PENDING, AUTHORIZED, CHARGED, PAID, one payment reference per trip.

Locked out of a login

Both login screens can now get you back in without anyone deleting or recreating a Firebase account:

The floating trip messenger

A πŸ’¬ button now sits in the top right corner of the Rider app and the Driver app. It stays hidden until a driver accepts the ride, then it appears with an unread badge, and it opens a popup messenger for that trip.

Every place a rider can exist

The rider panel now collects riders from four sources and merges them, richest record first:

  1. riders/{uid} in the registration project, written by the registration page;
  2. riders/{riderId} in the canonical project, written by the Rider app;
  3. users/{uid} with role: "Rider", in either project, which the registration page also writes;
  4. riders rebuilt from the trips they took.

The note under the table now names each source with its count, or NOT READABLE and the Firebase error code when the rules refuse a read. adminRiderSources() in the browser console returns the same thing as data. An empty panel can now be explained in one glance instead of guessed at.

The registration app writes to the other project

The registration page (registrationlogin.html) creates the Firebase Authentication account and then writes riders/{uid}, drivers/{uid} and users/{uid} into rider-s-drivers-info. The Admin dashboard was reading riders from driver-pro-card-login only. Drivers appeared because the driver list was already merged across both projects; riders were not. That is the whole reason the Registered Passengers table stayed empty while people were registering.

Admin now listens to riders in the registration project as well and merges three sources: registered riders, the records the Rider app saves, and riders rebuilt from the trips they took. The note under the table counts each source.

The registration record also carries safe card metadata, which is now shown: cardBrand, cardLast4, paymentMethodType, paymentMethodStatus, paymentMethodId and paymentMethodAddedAt. The registration page deliberately does not store the card number or the security code, and Admin displays only the brand and the last four digits.

One thing to fix in the registration page: it also writes the rider's and driver's password into the database in plain text. Admin never displays it and warns when it finds one, but it should not be there at all: the Firebase Authentication account is what signs people in, so that field is redundant.

Why the rider panel looked empty

The panel was correct, the data was not there. Two causes, and the old code could not tell them apart:

On top of that, the passenger list no longer depends on the riders node existing at all. Every trip carries riderId and riderName, so Admin rebuilds the list from ride history and merges the saved profiles on top when they are readable. A rider who has taken a trip is always listed, with their trips, fares and payments, and the note under the table says which source the rows came from.

Rider information and payments in Admin

What the rider record already holds. One writer, one path: the Rider app writes riders/{riderId} in the canonical project with riderId, fullName, email, phone, createdAt, lastSeen and source. The rider id is generated on the device and kept, so it survives page loads. Admin was already listening to that exact path, so there was no database mismatch to fix: the data was simply thin, and the dashboard only showed four columns of it.

What the payment system holds. There is no payment provider connected, so there is no card brand field, no last4 field, no payment method id and no processor transaction id. What exists per trip is paymentMethod (the label the rider chose), paymentStatus, paymentReference (derived from the tripId), paymentUpdatedAt, estimatedFare, finalFare, tipAmount and, after a failure, paymentAttempts. Reporting that is the honest answer: no card storage was invented to fill the gap.

Added to Admin, reading those same records:

The Rider app also gained a small My Details box (name, email, phone) that writes into the same riders/{riderId} record, because nothing in the apps ever collected an email or a phone number. It merges, so a blank field never wipes something already stored, and no second rider record is created.

The missing driver profile

A Firebase Authentication account and a database record are two different things. Creating the user, in the Firebase console or anywhere else, does not create drivers/{uid}. Nothing in these three apps ever created it: every drivers/{uid} write in the whole project is an update() for approval, presence or GPS that assumes the record already exists. There has never been a registration flow in the Rider, Driver or Admin file, only error messages that mention one. That is why a driver can sign in successfully and still be told there is no profile.

Added, without deleting or resetting anything:

Run driverProfileDiagnostics() in the browser console on the Driver app, after signing in, for a straight answer about the live database: the account, the UID, which project holds the session, whether the profile exists, every path that was checked with found, absent or denied, and any other record carrying the same email.

Driver sign in

Same shape as the admin problem. The Driver app signs in against rider-s-drivers-info and nowhere else, so a driver whose Firebase account was created in driver-pro-card-login could never get past the login screen, whatever they typed. What changed:

Run driverSyncStatus() in the browser console on the Driver app to see the signed in account, which project holds the session, where the profile was found, the approval state, the current trip and the last GPS fix.

Admin sign in

The Admin dashboard used to sign in against one project only: driver-pro-card-login. If the admin user was created in rider-s-drivers-info instead, the login could never succeed, and the only feedback was a bare "Login failed" box. Two changes:

The authorized address is still driverandridersapp@gmail.com. Typing anything else says so instead of failing silently. If a second admin address is needed, it goes in the ADMIN_EMAILS list in the Admin app.

When a driver has to call off a ride

A driver who has accepted a ride now has a red Cancel Trip button with the other trip buttons. It opens a panel of eleven reasons, one tap each: rider didn't show up, rider requested cancellation, safety concerns, no car seat, too many riders or luggage, inconvenient trip or personal reason, vehicle problem, wrong pickup location, rider not responding, emergency, and other. Only "Other" asks for a sentence, and Confirm Cancellation stays shut until one is written.

Driver registration, approval and access control

Registering as a driver no longer opens the Driver App. The application is saved to the Realtime Database with the status PENDING_APPROVAL, and the driver is told it is waiting for Rider’s Administration.

Country of Application, and telling a driver what was decided

Driver and passenger registration now both ask, and require, a Country of Application. The country and its two letter code are saved with the application, along with what that country was set to at the moment they applied.

The driver approval statuses are unchanged: PENDING_APPROVAL, APPROVED, REJECTED, SUSPENDED. Passwords are no longer written to the Realtime Database at all: Firebase Authentication is the only thing that checks one.

Deleting a passenger actually deletes them

Delete in Registered Passengers / Riders used to look as if it did nothing. A passenger can exist in five places, and it only cleared two of them, both in the canonical project. Anyone who signed up on the registration page lives in the other Firebase project, so their row came straight back on the next snapshot.

Removing a card is one wallet, and now says so

The card on a Rider’s account pays for rides and for package deliveries. Removing it from the delivery screen used to be one tap on a button marked "Remove card", which could quietly take away the card a rider pays for rides with.

There is still one Stripe wallet: no second customer and no second card store.

πŸ†˜ Support, πŸ’¬ chat and πŸ“ž Call Rider

πŸ“± The Admin app, on your phone

A private Admin app for company use, for phones and tablets. It is the same office system, laid out for a screen you hold in one hand. The desktop panel is untouched.

βœ… Approving a new passenger

πŸ‘€ Rider Registration is now a waiting list: new passengers who have signed up and are waiting for you to say yes.

πŸ‘€ Rider Registration, in the office

A new section under Driver Approvals, showing everybody who has registered as a passenger. Nothing else on the page moved.

πŸ›‘οΈ Payment security

Money is now decided in one place: the server, with Stripe. The apps ask; they never confirm. Nothing about how a ride looks or works has changed.

πŸ—ΊοΈ Every rider and driver, and where they are

One list in the office panel that answers the question "where is the business actually happening", so growth can be decided on figures rather than a feeling.

πŸ’± Canada, in Canadian dollars

Rider's prices a ride once. A passenger in the United States is quoted and charged in US dollars; a passenger in Canada is quoted and charged the same ride in Canadian dollars, worked out from that one US fare.

πŸ’³ The ride pays for itself

A finished ride used to sit there waiting for the passenger to notice a Pay button. Now the card on the account is charged the moment the driver ends the trip.

πŸ’³ Saved cards work now

A card saved on an account could not always be charged, and this is why: a saved card belongs to a Stripe customer, which is remembered against the id the sign in gives, while a ride carries the id the app made on the phone. Two different names for the same person.

🀝 Talking to each other, without swapping numbers

A driver and a passenger who have never met have to find each other at a kerb. That is the one moment they need to talk, so that is the moment this opens, and it closes again by itself.

πŸ‘€ No name, no ride

A driver pulling up needs to know who they are collecting, and the office needs to know whose ride it was. So a ride now carries a real name, or it is not requested at all.

πŸ‘€ Two passenger lists, told apart

The office had one table, and it mixed two different things: people who registered, and people who only exist in the rides they took. Four rides looked like four registered customers.

The 🌐 Language section is untouched.

πŸ‡ΊπŸ‡Έ πŸ‡¨πŸ‡¦ United States first, Canada second

πŸ‘₯ Clearing out your own test passengers

The passengers left over from your own testing look like real customers, so the 🧹 Prepare for LIVE scan will never propose them: that caution is deliberate, because it must never delete a genuine passenger. So the panel now lets you tick them by hand.

One thing to expect: removing rides removes their money from the earnings totals. That is the point of clearing test data before launch, and the backup taken a moment earlier holds all of it.

πŸ‘€ The passenger list in the office

The Registered Passengers / Riders table showed Beatris in the Rider Name column for everybody, because that is the name the old rides were recorded under.

πŸ‘€ Passengers are called by their own name

Every ride in the office said Beatris, whoever took it. That name was written into the Rider app as a placeholder in the original build and used whenever a device had nothing else stored, so four different people with four different email addresses all arrived under one name.

πŸ—‘οΈ Deleting a support conversation

Every support conversation in the office now has a Delete button: on its card in 🎧 Rider Support Chats and in πŸ“¦ Package Delivery Support, and inside the conversation when it is open.

βšͺ Notification text in white, at 16px

Notification and alert text is now white and 16px, on the same black background it was always on. (It was red, then briefly the company orange, and is now white.) 16px is the size a phone reads without squinting, and the size that stops iPhones zooming the page.

πŸ›οΈ Rider's Store, in the Rider app

The store is now in the Rider app as well, on a πŸ›οΈ Rider's Store row in the menu that opens it inside the app.

🎧 Support, on every page

The Rider app and the Driver app each have a support screen already. Every other page had nothing: someone reading the terms, on the install page, or halfway through registering had to find their way back into an app before they could ask anything. There is now a floating 🎧 Support button on all of them.

🧾 Balance due: order now, pay as you drive

A driver who cannot pay today still needs the sticker, and still needs to work. So an order can be placed with no money at all.

Most important: owing the store money never stops, suspends or restricts a driver. Nothing about the store is consulted by the rules that decide who may work. A driver with a balance goes online, is offered rides, accepts, drives and is paid exactly as before, and the app says so in as many words: "It comes off your earnings as you drive. You can keep working as normal." There is a test that drives a whole ride with a balance outstanding to prove it.

The office sees the balance on each order and the total owed at the top of the driver orders list.

πŸ“¦ Shipping & Driver Information on every store order

Every order in the Admin store now carries a πŸ“¦ Shipping & Driver Information section: the driver's full name, email, phone number, street address, city, state and ZIP code.

πŸ’³ Paying for a store order: card, or your earnings

At checkout in the Driver app there are now two ways to pay, and every order records which was used.

πŸ’³ Pay with card

πŸ’° Pay from Rider's earnings

The office sees which way each order was paid on its card in the Admin store. The price on an order is still the price it was placed at: a later price change never alters an order that has already been made.

πŸ–ΌοΈ The product picture upload, fixed

Uploading a product picture in the Admin store failed with Cannot read properties of undefined (reading 'getProvider'). The cause was in our own code, not in Firebase: the upload passed driverAccountsApp, the function that returns the app, where Firebase Storage expected the app itself. It looked for something on a function, found nothing, and threw. It is called properly now, and the app the admin is signed in to is tried first, so the upload carries a token the storage rules recognise.

πŸͺŸ The windshield sticker rule, in the Driver app

The company's own words about the sticker are now at the top of the store in the Driver app, where a driver cannot miss them:

Rider's Transporthers Front Windshield Sticker
MANDATORY DRIVER EQUIPMENT

Every active Rider's Transporthers Driver is required to display an official Rider's Transporthers sticker on the front windshield of the vehicle while providing transportation services.

The sticker helps riders easily identify an authorized Rider's Transporthers vehicle and provides a professional, consistent company appearance.

Important: This sticker must be clearly visible from outside the vehicle and properly placed on the front windshield.

One sticker is required for each active Driver vehicle.

πŸ›οΈ Rider's Store

A shop the office runs itself, for its own drivers. Everything in it lives in the database, so new products, prices and pictures are added from the Admin panel without anybody touching the site.

In the Admin panel

In the Driver app

The first product is the Rider's Transporthers Front Windshield Sticker, created for you and marked as required. It is an ordinary product record: change its price, picture or wording whenever you like.

πŸ’³ The card is authorised before the ride is created

A ride used to be created, sent to a driver and sometimes driven before anybody discovered the card would not pay for it. The bank is asked first now:

πŸ’³ The Stripe key in the browser now comes from the server

Stripe reported: "The publishable key in the browser belongs to a DIFFERENT Stripe account from this secret key." The publishable key was written into the app's code, so it could not follow the LIVE secret key installed on the server.

The secret key is never sent to the browser, never stored in Firebase and never written into any page or log. Only the publishable key, which is public by design, is.

🧹 Clear Test Data / Prepare for LIVE

An admin-only panel that removes the accounts, rides, deliveries, conversations and GPS trails made while testing, and nothing else. It never runs by itself: there is no timer and no schedule, only four deliberate steps.

Never touched, whatever is ticked: the app itself, prices, app configuration, Stripe keys, Firebase and its authentication, the security rules, the database structure, the support system and its quick answers, and the admin account. Those names are on a protected list, and a second check refuses them again at the moment of deletion.

Afterwards the office is shown exactly what went: test riders, drivers, trips, deliveries, support conversations, notifications, chat records, GPS records and payment records, along with the backup it can be restored from. Anything the database refuses is reported, never swallowed.

🎧 Two support desks: rides and package deliveries

Support in the Admin panel is now read at two desks instead of one long list:

🚘 Who is picking me up

The Rider app now shows, from the moment a driver accepts until the ride ends:

It is also on the popup that appears the moment the ride is accepted, which now names the car and the plate as well as the driver.

πŸ†˜ Support answers you now

Support was reaching the office, and the office could answer, but nothing came back until somebody was at a desk. A message sent at two in the morning sat in silence. It is answered straight away now, in the same conversation.

The big roads are the company orange now

πŸ“… Company earnings, by the month

The copyright line, on every page

© 2026 RIDER’S LLC. All Rights Reserved. now sits at the foot of every page, in the same words everywhere.

πŸ“€ Share this app

The ride request arrives in the middle of the driver's screen

The rider's card stays on file

πŸ—ΊοΈ A live driver map for the office

A Live Driver Map button beside the live rides panel opens the whole fleet on one map, in its own window.

Every Stripe payment now names the ride it paid for

A payment of $27.97 in Stripe used to say only "trip REQ-...". Opening one now answers everything on its own.

πŸ“£ The office can send a message to one rider or one driver

Admin has a Send a Notification panel: pick a passenger or a driver, pick the person, write the message, send.

The Driver Console header, rearranged

🚦 Signals, stop signs and live traffic on the map

Address entry: three more ways the screen could change, all closed

The 16 pixel fields were right, but they were not the whole story. Measured on a phone-sized screen with the real map loaded, the page itself never rescales. Three other things could still make it look as though it had:

Pinch to zoom still works everywhere, nothing forces a zoom level, and the map keeps every bit of its own behaviour.

Typing an address no longer zooms the screen

Tapping the pickup or destination box on an iPhone used to zoom the whole page in, and it did not zoom back out, so the map and everything around it looked wrong afterwards.

πŸ‘₯ Refer friends, in both apps

Riders and drivers now have an invite screen in their menu: Refer friends.

πŸ” Drivers can navigate to a destination of their own

A round 🔍 button now sits in the top right corner of the driver's map, and of the navigation screen. It is 52 pixels across, dark with a white ring, so it can be found and hit at a glance.

The logo is bigger

The mark in the app headers went from 36 to 50 pixels, the logo over the sign in went to 200, and the size it shrinks to on a short screen went from 96 to 140. It was getting too small to read.

The passenger sees the same drive, live

The Rider app now has the driver's navigation screen, written for the person in the back seat. Nothing was rebuilt: the booking, the fare, the payment, the chat and the map are all the ones that were there.

Turn by turn, the way the reference picture looks

The instruction at the top of the driver's map was rebuilt to match the navigation screen the owner sent.

The driver map is a navigation screen now

The same map, the same route, the same trip. What changed is how it behaves while the driver is driving.

Drivers stay signed in, and prove who they are

Two changes to the Driver app, both additions.

πŸ”Ž Rider’s Lost & Found Return Policy

Something left in a car now has a route home, and a policy of our own behind it.

Drivers are paid by Stripe, every Friday

The 40/60 split is now made by Stripe at the moment the rider pays: the driver's 40% and their whole tip go straight into their own connected Stripe account, and Rider’s 60% is taken as the platform fee. Nobody has to move money afterwards, and the company never holds the driver's share.

Saved cards: add, choose, remove

A rider can now keep more than one card, choose which one pays, and remove an old one. It is one wallet for both services: the card marked as the default is what every ride and every package delivery is charged to.

Paying for a package delivery

The delivery form now has its own payment block. Ride payments are untouched.

πŸ“¦ Rider’s Package Delivery

A second service beside the ride, built on the same machinery: a delivery is a trip, with the same driver claim, the same live GPS, the same chat, the same payments and the same cancellation. Nothing about the ride service changed, and every job recorded before today is still a ride.

Turn by turn navigation

Accepting a job now opens a full screen navigation on the Driver app, and the passenger watches the same ride from their own screen. Both are built on the map, the router, the GPS and the trip record that were already there: there is one of each, not a second navigation system beside the first.

The maps no longer open zoomed out

Both apps opened on a fixed point with most of Palm Beach County on screen, and only came in close a few seconds later. That opening view is what looked like the app zooming out.

The phone, not the website, is handing links to the Driver app

An app installed on Android from a website registers itself with the phone for every address its scope covered at the time it was installed. The Driver app was installed when it claimed the whole site, so the phone hands it every link to riderstransporthersllc.com, the Admin page included. Nothing on the server can override a claim that lives inside an app already on the phone.

If it still opens in the Driver app

A phone keeps an installed app's settings until that app updates itself. A Driver app installed before this change still claims every page on the website, so the Admin page keeps opening inside it even though the settings on the server are now correct.

  1. Open the Driver app from its icon, wait a moment, close it. Do that twice: that is what makes the phone fetch the app's new settings.
  2. If it still happens, press and hold the Driver icon, remove it, then open riderstransporthersllc.com/driver.html in the browser and install it again.
  3. Then open riderstransporthersllc.com/admin.html in the browser and install the Admin app.

The Admin page now tells you when it is running inside another app, with a button to open itself in the browser, and it has a Check this phone button that reports what the browser thinks is going on.

Why Install opened the Driver app

All three apps described themselves with a scope of /, which means "every page on this site belongs to me". On a phone that already had the Driver app installed, opening the Admin page opened it inside the Driver app, and Install offered to open it there rather than install a separate app.

What to check on the live databases

Back to the app launcher