bike-guide-app/
A cycling companion for Filipino beginner and intermediate riders. Sixteen pages of hand-written HTML, CSS and JavaScript that installs like an app, works with no signal, and explains the one thing nobody explains: which gear to be in.
Twenty-one gears, and nobody explains any of them
New riders here buy a bike with 21 gears and never get told what any of them are for. The advice online is written for other countries, with other roads, other traffic and other weather, and it assumes a data connection on a ride where there often is not one.
A gear simulator, routes, and a ride recorder
- Gear guide and simulator. Tap any front-ring and rear-cog pair to see the ratio, the terrain it suits, and whether it cross-chains. Uphill, flat, downhill and sprint each get their own explanation.
- Routes. Curated Philippine rides with distance, elevation, difficulty, best time to go, and what the traffic is like.
- Ride recorder. Live GPS tracking for speed, distance and route map, through the Geolocation API.
- A 30-day challenge, plus maintenance, safety, warm-up, diet and a carbon-saved calculator.
Built by hand, to find out what a framework was doing
No framework, no bundler, no package manager. That was the point. Building a PWA by hand is how you find out what a framework has been doing for you: the service worker and its cache-versioning discipline, the offline fallback page, the install manifest, and the fact that a stale cache is the most common way to ship a change that appears not to work.
Identity turned out to be the interesting bug. The first version
identified a rider by a crypto.randomUUID() kept in localStorage and
sent as part of the Firestore document path. The rules engine cannot verify a
value like that, since a caller claims whichever ID it likes, so ownership was
unenforceable and anyone who learned a UUID could read that rider's history. It
now signs in with Firebase Anonymous Authentication and ownership
is checked server-side against request.auth.uid. Same invisible
experience for the rider, with an actual boundary underneath.
firestore.rules, which is why those rules
have their own test suite running against the real emulator in CI.