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 |
|
| Item | Notes |
|
||||||
|---|---|
|
|---|---|
|
||||||
@@ -119,7 +180,7 @@ What still holds regardless:
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 5. Ideas
|
## 6. Ideas
|
||||||
|
|
||||||
Terse on purpose. Unshaped, to be consolidated later.
|
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.
|
polished rather than merely clean.
|
||||||
- **User sign-up and accounts.** Register people, give their data somewhere to live.
|
- **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.
|
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
|
- **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.
|
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
|
- **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,
|
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.
|
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
|
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
|
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.
|
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
|
1. [../README.md](../README.md) — what the app is and its current state
|
||||||
2. [ARCHITECTURE.md](ARCHITECTURE.md) — why it is built this way
|
2. [ARCHITECTURE.md](ARCHITECTURE.md) — why it is built this way
|
||||||
|
|||||||
Reference in New Issue
Block a user