v3: promote activity type from an idea to a specified item
It turned out to be a positioning decision rather than a feature -- it decides the store category, the screenshots and who finds the app, and cyclists are a much larger audience than motorcyclists. Far cheaper to settle before a store listing exists. Specified the schema (a text enum on Trip), and flagged that this is the first real migration the port will ship: the destructive fallback is gone, so it needs addColumn with a motorcycle default, schemaVersion 2, and a test that opens a v1 database and asserts the rides survive. Getting that path right matters more than the feature. The value is in driving per-activity defaults rather than labels: the 1.5 km/h noise floor is wrong for walking, 10 km/h histogram buckets are useless for running, and the elevation smoothing window was tuned for 2 Hz road speed. Also recorded a UI constraint: no picker in front of Start. The founding premise is press-and-go with gloves, so default to the last activity used and make it editable on trip detail afterwards. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -104,7 +104,68 @@ What still holds regardless:
|
||||
|
||||
---
|
||||
|
||||
## 4. Smaller items
|
||||
## 4. Activity type per ride
|
||||
|
||||
Promoted out of the ideas list, because it turned out to be a **positioning decision**
|
||||
rather than a feature. See [LAUNCH.md](LAUNCH.md).
|
||||
|
||||
Everything user-facing says motorcycle, but the recording pipeline never did: it records
|
||||
positions, speeds and altitudes, and nothing in it cares what you are sitting on. Dylan
|
||||
already rides both bikes and motorcycles.
|
||||
|
||||
**Why it matters beyond the feature:** it decides the store category, the screenshots and
|
||||
who ever finds the app. Cyclists are a far larger audience than motorcyclists and are
|
||||
already used to paying for ride apps. That question is much cheaper to settle before a
|
||||
store listing exists than after.
|
||||
|
||||
### Schema
|
||||
|
||||
An `activity` column on `Trip`, stored as a text enum like `TripState`:
|
||||
|
||||
```
|
||||
motorcycle · bicycle · scooter · skateboard · running · walking · other
|
||||
```
|
||||
|
||||
This is the **first real migration** the port will ship. The destructive fallback is gone
|
||||
for good, so it needs `m.addColumn(trips, trips.activity)` with a default of `motorcycle`
|
||||
for existing rows, `schemaVersion` bumped to 2, and a migration test that opens a v1
|
||||
database and asserts the rides survive. Getting that path right once matters more than the
|
||||
feature does — every later schema change depends on it.
|
||||
|
||||
### Type should drive defaults, not just labels
|
||||
|
||||
This is where the real value is, and it is easy to miss:
|
||||
|
||||
| Setting | Why it differs |
|
||||
|---|---|
|
||||
| Speed noise floor (1.5 km/h) | Fine for a motorcycle; wrong for walking, where real movement lives near it |
|
||||
| Speed histogram bucket (10 km/h) | Useless for running — everything lands in one bucket. Wants ~1 km/h. |
|
||||
| Accuracy gate (50 m) | A motorcycle at speed can tolerate looser fixes than a walker |
|
||||
| Elevation smoothing window | Tuned at 15 samples for 2 Hz road speed; a slower activity covers less ground per sample |
|
||||
| Map fit zoom | A 2 km walk and a 200 km ride want different defaults |
|
||||
|
||||
Treat these as a per-activity profile rather than scattering `if (activity == …)` through
|
||||
the code.
|
||||
|
||||
### Do not put a picker in front of Start
|
||||
|
||||
The founding premise is press-and-go with gloves on. A modal asking "what are you doing?"
|
||||
before recording begins would undo that.
|
||||
|
||||
Better: **default to the last activity used**, and make it editable on the trip detail
|
||||
screen afterwards, next to rename. Most people do the same thing most days, and the one
|
||||
time they don't, they can fix it after.
|
||||
|
||||
### Follow-ons, once the column exists
|
||||
|
||||
- **Filter and group the trips list** by activity
|
||||
- **GPX `<type>` on `<trk>`** — Strava and Garmin read it, so an exported ride imports as
|
||||
the right activity instead of defaulting to something wrong
|
||||
- Per-activity totals, if a stats screen ever appears
|
||||
|
||||
---
|
||||
|
||||
## 5. Smaller items
|
||||
|
||||
| Item | Notes |
|
||||
|---|---|
|
||||
@@ -119,7 +180,7 @@ What still holds regardless:
|
||||
|
||||
---
|
||||
|
||||
## 5. Ideas
|
||||
## 6. Ideas
|
||||
|
||||
Terse on purpose. Unshaped, to be consolidated later.
|
||||
|
||||
@@ -130,11 +191,6 @@ Terse on purpose. Unshaped, to be consolidated later.
|
||||
polished rather than merely clean.
|
||||
- **User sign-up and accounts.** Register people, give their data somewhere to live.
|
||||
Prerequisite for anything cloud-side, and pairs with the group-ride server in section 2.
|
||||
- **Activity type per ride.** Motorcycle, bicycle, skateboard, running, other. The app is
|
||||
not inherently motorcycle-only — the recording pipeline is activity-agnostic already.
|
||||
Note: adds a column to `Trip`, so it needs a real `Migration` (the destructive fallback
|
||||
is gone). Type could also drive sensible defaults — speed noise floor, map zoom,
|
||||
elevation smoothing.
|
||||
- **Paid cloud backup.** Ongoing storage of rides over time. Needs accounts first, plus a
|
||||
decision on hosting, pricing, and what happens to data when someone stops paying.
|
||||
- **Waypoint route planning.** Drop a series of pins on the map to "draw" a route, get
|
||||
@@ -151,7 +207,9 @@ Terse on purpose. Unshaped, to be consolidated later.
|
||||
Sign-up, cloud backup and group ride are one programme, not three: they all need a server,
|
||||
identity, and a privacy stance. Worth scoping together rather than separately.
|
||||
|
||||
Activity type and theming are independent and much cheaper — either could ship alone.
|
||||
Activity type (now section 4) and theming are independent and much cheaper — either could
|
||||
ship alone, and activity type is the natural first v3 task because it forces the migration
|
||||
path to be proven while the stakes are still low.
|
||||
|
||||
Live map, handlebar mounting and waypoint following also cluster: all three assume a
|
||||
visible screen during the ride, and all three want the same map component. Route planning
|
||||
@@ -160,7 +218,7 @@ standalone.
|
||||
|
||||
---
|
||||
|
||||
## 6. Things that must not regress
|
||||
## 7. Things that must not regress
|
||||
|
||||
Hard-won and easy to undo by accident. Each has a comment in the code explaining why.
|
||||
|
||||
@@ -181,7 +239,7 @@ Hard-won and easy to undo by accident. Each has a comment in the code explaining
|
||||
|
||||
---
|
||||
|
||||
## 7. Reading order for picking this up cold
|
||||
## 8. Reading order for picking this up cold
|
||||
|
||||
1. [../README.md](../README.md) — what the app is and its current state
|
||||
2. [ARCHITECTURE.md](ARCHITECTURE.md) — why it is built this way
|
||||
|
||||
Reference in New Issue
Block a user