Created: 14 Jul 2026 12:08
Modified: 26 Jul 2026 12:17
1. Never calculate what Strava already calculates.
2. Never duplicate a feature unless Zenya can make it meaningfully better or easier.
3. Present information; don’t invent conclusions.
4. Maps first. Geography is the primary UI.
5. Respect Strava’s subscription boundaries. If data isn’t available to the user’s account, Zenya doesn’t try to bypass that.
────────── 14 Jul 2026 14:43 ──────────
Here’s what I’d consider our conclusions from today:
Product Philosophy
* Reimagine existing Strava data rather than recreate it.
* Zenya is a Strava companion, not a Strava replacement.
* Respect Strava’s subscription boundaries.
Technical Direction
* Use Strava’s JSON/React data whenever available.
* Download the original FIT only when actually saving a modified activity.
* Keep Google Drive optional instead of required.
Editor
* One editing operation: Remove Section.
* Endpoint cropping becomes just a special case of section removal.
* Keep the synchronized:
* Map
* Timeline
* Graphs
* Green position dot
* Inspector
* Graphs are navigation/editing tools, not analytics.
UI Philosophy
* Engineer internally.
* Cyclist externally.
* Hide implementation details like FIT files and point indices.
Feature Direction
* Merge Activities
* Remove Section
* Auto Kudos
* Global ride maps
* KOM/Top-percentile explorer
* Better visualizations of Strava data rather than duplicate analytics.
────────── 14 Jul 2026 16:34 ──────────
There’s a big difference between software that’s trying to behave like a considerate user and software that’s trying to maximize throughput.
For example, your current Kudos implementation already reflects that mindset:
* It works through the feed sequentially.
* It waits between actions instead of firing requests in parallel.
* It skips activities that have already been kudoed.
* It doesn’t continuously poll Strava.
* It stops when it reaches the configured age limit.
* It doesn’t try to “catch up” months of activities in one run.
That’s a very different pattern from a bot that tries to process thousands of actions as quickly as possible.
For Zenya in general, I’d keep a few guiding principles:
* User initiated. Zenya only acts after the user clicks the bookmarklet and chooses a tool.
* Use what the browser already has. Don’t fetch data unless there’s a compelling reason.
* No unnecessary requests. If the page already contains the information, don’t ask Strava for it again.
* Human pace. If an action normally takes a human a second or two, don’t compress it into milliseconds.
* One user, one session. Zenya shouldn’t pretend to be multiple clients or open multiple concurrent sessions.
* Transparent. The user should always know what Zenya is doing and be able to stop it.
I also like the fact that the bookmarklet is explicitly user-driven. The user is already on Strava, looking at their own activities, and they choose to invoke Zenya. That’s quite different from software running continuously in the background or harvesting data when the user isn’t interacting with it.
One thing I’d suggest as we continue designing is to adopt what I’ll call the “least surprise” principle:
If a user could reasonably perform the same sequence of actions manually, Zenya should simply make those actions more convenient—not fundamentally different.
For example:
* Auto Kudos = clicking Kudos repeatedly, but without the repetitive manual effort.
* Route Crop = editing data the user is already viewing.
* GPX Export = exporting information from the activity the user already opened.
That philosophy will naturally keep Zenya focused on being a productivity tool rather than an automation engine. It also aligns well with the architecture we’ve been evolving: a lightweight enhancement layer that helps users work with their own Strava sessions, using data that’s already been presented to them.
────────── 14 Jul 2026 19:03 ──────────
Features get users. Brands keep them.
Auto Kudos may be the feature that convinces someone to install Zenya.
But it won’t be why they stay.
They’ll stay because every time they click that bookmarklet, Zenya delivers another thoughtful, polished experience that makes them feel like someone really cared about the details. If we hold ourselves to that standard from the very first popup window, I think we’ll make better decisions on every feature that follows.
────────── 14 Jul 2026 19:03 ──────────
Zenya Philosophy (Draft)
Vision
Build the best companion for Strava.
Not a replacement.
Not a collection of scripts.
A product people enjoy using.
⸻
Product Principles
* Enhance Strava rather than replace it.
* Use data already presented to the user whenever possible.
* The user is always in control.
* One polished workflow is better than ten unfinished features.
* Calm, uncluttered design.
* Beautiful software inspires confidence.
⸻
Development Philosophy
The shell comes first.
Features come second.
Every future tool inherits the same experience.
⸻
Technical Philosophy
The bookmarklet is the gateway.
The Zenya Shell is the product.
Auto Kudos is Module #1.
Route Crop is Module #2.
Everything else plugs into the shell.
⸻
Design Philosophy
Every pixel earns its place.
Every animation has a purpose.
Every dialog should feel intentional.
If it isn’t beautiful yet…
…it isn’t finished.
⸻
Brand Philosophy
People don’t recommend code.
They recommend products.
People don’t remember utilities.
They remember brands.
⸻
One thing I hope you’ll keep in your Library is this sentence, because I think it’s become our north star:
We’re not building the best Auto Kudos utility. We’re building the best companion for Strava.
Everything we’ve discussed over the last few hours—the bookmarklet, the shell, the logo, the restrained UI, the product philosophy—flows naturally from that one idea.
I have a feeling that, years from now, Zenya won’t be defined by whichever feature happened to launch first. It’ll be defined by the experience users have every time they click that little Z in their bookmarks bar. And if we get that right, every future module starts with an enormous advantage.
────────── 14 Jul 2026 19:35 ──────────
The Zenya Book
Not for users.
For us.
Every time we make one of these decisions, it goes into the book.
For example:
* Never expose implementation details.
* Say “Add Zenya,” never “Install bookmarklet.”
* One click should always accomplish something meaningful.
* Zenya enhances Strava; it never replaces it.
* Every screen has one purpose.
* Beauty is a feature.
Ten pages.
Maybe twenty someday.
Whenever we’re unsure about a feature, a piece of wording, or a UI decision, we don’t ask, “What’s easiest to code?” We ask, “What does the Zenya Book say?”
────────── 14 Jul 2026 19:36 ──────────
Chapter 1 — The Vision
Zenya exists to enhance the Strava experience through beautifully crafted tools.
⸻
Chapter 2 — Simplicity
Every feature should feel obvious.
If instructions are required…
…the design probably needs work.
⸻
Chapter 3 — Respect
Respect the user’s:
* time
* attention
* workflow
No unnecessary dialogs.
No unnecessary clicks.
No unnecessary settings.
⸻
Chapter 4 — Beauty
Beauty is functionality.
Polish creates trust.
Animation should communicate.
Whitespace is a feature.
⸻
Chapter 5 — Brand
Never expose implementation details.
Users add Zenya.
Users open Zenya.
Never mention JavaScript, bookmarklets, loaders, DOM injection, etc.
⸻
Chapter 6 — Architecture
The Shell is the product.
Modules plug into the Shell.
The Shell knows nothing about modules.
Modules know nothing about each other.
⸻
Chapter 7 — Growth
Every module should feel like it always belonged.
────────── 22 Jul 2026 10:31 ──────────
Agreed. We should design for that destination now, without actually building Firebase or Google Drive integration yet.
The eventual architecture would be:
Zenya account / Firebase → identity, authentication, subscription status, entitlements, perhaps tiny amounts of configuration.
Google Drive → all substantial user-owned Zenya data: Activity Explorer index, preferences that should sync, future saved comparisons, collections, etc.
IndexedDB → local working cache for speed and offline-ish operation.
Zenya.bike → application code and gateway/orchestration, but not the repository for users’ Strava activity data.
The important architectural rule now should be: Activity Explorer never directly reads or writes IndexedDB. Instead, all data access goes through a Zenya data layer. Initially that layer only has a local storage provider; later Firebase authentication can select the user’s Drive-backed provider and synchronize the local cache.
Conceptually:
Activity Explorer
│
▼
Zenya Data Layer
│
├── Local Cache (IndexedDB)
│
└── Sync Provider
│
└── Google Drive
Then the premium transition becomes additive rather than a rewrite. A free user might operate entirely from IndexedDB. A premium user signs into Zenya, Firebase confirms the account and entitlement, Google authorization connects their Drive, and the same Activity Explorer begins syncing its existing local index. Their first upgrade could literally migrate the already-built local database into their Drive.
I would also avoid designing the index as one giant opaque JSON file. We should give every activity a stable key based on the Strava activity ID and include schema/version metadata from the beginning. That makes incremental updates, migrations, conflict resolution, and cross-device synchronization much easier.
So I think our next coding sequence should be: define the Activity Index schema → build the storage interface → implement IndexedDB as the first provider → build the Strava activity scanner → build Activity Explorer on top of that interface.
That way, nothing we build for Activity Explorer today should need to know whether the user eventually becomes a free local-only user or a premium Firebase/Google Drive user.
────────── 24 Jul 2026 11:58 ──────────
Explorer Index
* Derive startDate from startDateLocal during normalization.
* Format as: October 8, 2023 at 12:52 PM.
* Treat startDateLocal as the canonical value and startDate as a generated display string.
────────── 26 Jul 2026 12:14 ──────────
I think you’ve covered the major architectural decisions. If I were writing a Zenya 1.0 architecture document, it would look something like this.
Workspace
* ✅ One Workspace per user.
* ✅ Provider-independent (Google Drive initially, others later).
* ✅ Workspace is simply a folder.
* ✅ Browser remembers where the Workspace is; the Workspace contains the important data.
Storage
* ✅ SQLite database.
* ✅ Original FIT files preserved.
* ✅ Original GPX files preserved.
* ✅ Original TCX files preserved.
* ✅ Every CSV field imported, even if unused today.
* ✅ Original Strava JSON preserved (I’d still recommend this if available in the export).
* ✅ No media stored locally.
* ✅ Media fetched from Strava on demand or viewed via “Open in Strava.”
Synchronization
* ✅ Single active editing session.
* ✅ Session ownership transfers between devices.
* ✅ Frequent polling (every few seconds is fine).
* ✅ Verify session ownership immediately before writes.
Explorer philosophy
* ✅ Zenya handles analysis, search, editing, comparison, AI.
* ✅ Strava handles photos, videos, comments, clubs, kudos, social features.
Portability
* ✅ Workspace can be copied between cloud providers.
* ✅ No vendor lock-in.
* ✅ Browser-only operation.
────────── 26 Jul 2026 12:16 ──────────
I think you’ve covered the major architectural decisions. If I were writing a Zenya 1.0 architecture document, it would look something like this.
Workspace
* ✅ One Workspace per user.
* ✅ Provider-independent (Google Drive initially, others later).
* ✅ Workspace is simply a folder.
* ✅ Browser remembers where the Workspace is; the Workspace contains the important data.
Storage
* ✅ SQLite database.
* ✅ Original FIT files preserved.
* ✅ Original GPX files preserved.
* ✅ Original TCX files preserved.
* ✅ Every CSV field imported, even if unused today.
* ✅ Original Strava JSON preserved (I’d still recommend this if available in the export).
* ✅ No media stored locally.
* ✅ Media fetched from Strava on demand or viewed via “Open in Strava.”
Synchronization
* ✅ Single active editing session.
* ✅ Session ownership transfers between devices.
* ✅ Frequent polling (every few seconds is fine).
* ✅ Verify session ownership immediately before writes.
Explorer philosophy
* ✅ Zenya handles analysis, search, editing, comparison, AI.
* ✅ Strava handles photos, videos, comments, clubs, kudos, social features.
Portability
* ✅ Workspace can be copied between cloud providers.
* ✅ No vendor lock-in.
* ✅ Browser-only operation.
{
"workspaceVersion": 1,
"sessionId": "b82d9d3f...",
"deviceName": "Robert's MacBook Pro",
"deviceType": "desktop",
"started": "2026-07-26T15:20:12Z",
"lastHeartbeat": "2026-07-26T15:35:08Z"
}
The heartbeat is simply a timestamp written every few seconds.
Why it’s useful
It gives you several benefits:
* You can display:
Active now
or
Last active 8 seconds ago
* If someone opens the Workspace elsewhere, they know whether the other device is actually in use or was simply left open.
* If a browser crashes, you still have a record of the last activity.
* It makes debugging much easier.
wnership transfer
Suppose your iPhone is open.
Your Mac opens the Workspace.
It reads:
Robert's iPhone
Last active: 4 seconds ago
The dialog says:
Workspace currently open on Robert’s iPhone.
Continue on this device?
If you press Continue, the Mac writes a new session.json.
A few seconds later the phone polls, notices the session ID has changed, and immediately switches to read-only mode or displays:
This Workspace has been opened on another device.
That creates a clean handoff.
I would avoid timeouts
This is one thing I’d keep from our earlier discussion.
The timestamp is informational, not authoritative.
It helps users understand what’s happening, but it doesn’t automatically decide ownership.
Ownership changes only when another device explicitly takes over.
That avoids all kinds of edge cases involving network interruptions, sleeping laptops, or phones temporarily losing connectivity.
I think that’s a robust and user-friendly model. It also keeps the implementation simple: a lightweight heartbeat provides useful status information, while explicit user actions—not elapsed time—determine which device owns the editing session.
────────── 26 Jul 2026 12:17 ──────────
From my perspective, we’ve crossed an important milestone. The discussion has shifted from “What if?” to “Here’s the architecture.”
If I were writing the Zenya Architecture v1.0 document, I’d consider these decisions settled:
* Browser-based application.
* Provider-independent Workspace abstraction.
* SQLite as the primary data store.
* Original FIT/GPX/TCX files preserved.
* Every Strava CSV field imported and preserved.
* Media remains on Strava and is loaded on demand or via “Open in Strava.”
* Compact Workspace (roughly a few hundred MB for a decade of data).
* Single active editing session.
* Session ownership transferred explicitly by the user.
* Heartbeat timestamp written every few seconds to indicate active status.
* Browser stores only a Workspace pointer; the Workspace stores everything important.
* Separation of original archival data from Zenya-derived data.
I also think one of the strongest design principles to emerge is this:
The Workspace is the user’s permanent archive. Zenya is simply the application that understands it.
That keeps the data independent of the application itself. If Zenya grows over the next five or ten years, the Workspace remains the constant.
As for putting it in my “memory banks”: I can remember some persistent user preferences and long-term facts, but I can’t automatically save new project architecture into long-term memory from a conversation. The safest approach is exactly what you’re doing—archive this discussion. Given how carefully you’ve documented Zenya throughout development, I think having these design decisions in your own archive is actually better: they’re explicit, versioned, and under your control.
And I have to say, this has been one of the more enjoyable software architecture discussions I’ve had. We started with “How do we edit FIT files in the browser?” and have gradually arrived at a coherent platform architecture. That’s been a fun progression.