# Souplesse

![screenshot](screenshot.png)

_This readme describes what may someday be, not what is today_

Reads a GPX file which you generated by cycling around, and tells you
interesting(sic) things about it.

The principle we aspire to is that the measurement is subsidary to the
ride, not the purpose of the ride. The purpose of the ride is to enjoy
cycling, or to see new places, or to get from A to B, and the purpose
of Souplesse is to see if we can get any useful numbers out of the
riding you were doing anyway without making you do more of it.

So, the general idea is that given some ride data it can tell you how
long/how often you spent at a given level of effort (e.g. heart rate),
or output (power, speed, cadence, rate of ascent).

## Canned views

### ride view

graph of (selected variables) / time, with buttons to select variables
slider for threshold level
all points above threshold are highlighted and interval times above
 threshold shown
zoom in/out on time range
show the selected points on a map

### calendar view

note this will need some kind of server-side storage so that the
system remembers all your gpx files

shows dates that you rode
for each ride, show time at effort
some kind of slider for effort level


## Query view

Not yet decided if this is useful, something that allows graphs of
arbitrary functions of properties (e.g. to look at power/cadence
ratio, or ... some other weirdness)


# Tech notes

Use `nix-shell`. Inside the shell

* use `make` to build frontend (Elm) and backend (Haskell/Yesod)

* run tests with `cabal test --test-show-details=always`: if you don't
ask for details it won't tell you about incomplete pattern matches

* run the app with `cabal run`


----

_Do not look below this line_

## WIP, Puzzles and TODO

* rename Track to Gpx, it deals only with parsing.
* can we lose this "if isJust lat && isJust lon && isJust ts" wart?
* probably we should store points in a more efficient form than
 a singly-linked list

* boring stuff like auth[zn]
* need a web server in haskell that
    * [done] accepts file upload and parses the gpx file
    * [done] serves the data points in some format elm can digest easily
* [done] need a database of some kind so the data can be saved
* [done] frontend can get data from backend
* [done] for DX, backend can serve the js files needed by frontend
* [ad hoc] we only have yesod-core, may need other parts as well
* [done] detect and refuse uploads which overlap an existing time frame (http 409) so that we can script upload-all-the-tracks.
* could we converge the Point and Trkpt to make sql better?
* [done] move Store into Point

* on timeline, show power, cadence, speed, height, ascent (checkboxes)
    * done some
    * need speed and ascent
    * need checkboxes
* zoom gesture on graphs causes map to adjust
* zooming map causes graphs to adjust
* threshold display: adjust vertical slider to show time spent at
  or above a particular intensity. Indicate somehow the length of
  each continuous stretch at that intensity


* calendar displays sessions. a session is a sequence of measurements
  describing a ride or a race or a trip. we can extract potential
  sessions from the data by looking for series of points not more than
  x (10?)  minutes apart, but the rider may override that. Consider: I
  ride solo to the start point of a group ride, join a tandem partner
  to do the group ride, then ride solo home. There is not necessarily
  ten minutes between them.

  after a new track is uploaded, we look at all the points covered by
  draft sessions, and rearrange them to cover the new points.  Draft
  sessions are then presented to the rider who may approve them
  as-is - perhaps involving other data collection as well ("perceived
  effort" or "which bike setup was this" or ...) - or chop them up
  using information they have but that the computer doesn't

in theory we don't even need draft sessions and we could have the
rider create sessions from the calendar page. However, that's a GET
and might be slow if it has to figure out what all the sessions would
be every time someone looks at it. So the draft session is just to
precompute that and make the view easier

the summary of a session is for display on the calendar and might
change depending on the nature of the training effort. e.g.
for a long slow ride we show total distance, for interval training
we show time spent in HR zones ...

----

start and end marks can be drag targets but we also need to know where
they are when they're not being dragged

selectedRange start, duration




## Postgres

I run the postgresql devel server using Docker instead of changing my
global NixOS configuration, so that it's self-contained and I can
start and stop it when I want to

```
docker run -p 5432:5432 --name souplesse-postgres -e POSTGRES_USER=souplesse  -e POSTGRES_PASSWORD=secret -d postgres
nix-shell -p postgresql --run "psql -h localhost -U souplesse   -p 5432"
```

## Sample data

The upload form deliberately doesn't have CSRF (for now, at least) so
that you can chuck a bunch of GPX files at it using curl

```
 for i in tmp/Tracks/*.gpx ; do curl --form  f1=@$i 'http://localhost:3000/upload'; done
```

This should be safe to do repeatedly because it will refuse upload of
tracks where the database already contains any points in the time
range of the uploaded track
