Docs
This commit is contained in:
parent
4f382819fd
commit
8c6579b9bf
1
docs/architecture-portal.drawio
Normal file
1
docs/architecture-portal.drawio
Normal file
File diff suppressed because one or more lines are too long
BIN
docs/architecture-portal.png
Normal file
BIN
docs/architecture-portal.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 234 KiB |
196
docs/architecture.md
Normal file
196
docs/architecture.md
Normal file
|
@ -0,0 +1,196 @@
|
|||
# Portal Architecture
|
||||
|
||||
Here I try to describe how the portal works in general, and which parts are
|
||||
needed and developed in this repository. There is some variation possible for a
|
||||
full setup, for example the data flow of the rendered data tiles can be
|
||||
different. This article describes the standard production setup.
|
||||
|
||||
## General overview of the components
|
||||
|
||||
* **api**: A python process using sanic to provide a HTTP interface. Everything
|
||||
revolves around this.
|
||||
* **postgresql**: A database instance.
|
||||
* **frontend**: A React based web application.
|
||||
* **worker**: Optional, a dedicated process for processing of tracks
|
||||
* **keycloak**: An installation of [Keycloak](https://www.keycloak.org/) which
|
||||
stores user credentials and provides a secure login, registration, password
|
||||
recovery, and more.
|
||||
* **tools**: Scripts to run as an operator of the application for various setup
|
||||
and maintenance task.
|
||||
|
||||
![Architecture Overview](./architecture-portal.png)
|
||||
|
||||
## PostgreSQL
|
||||
|
||||
This is a database instance running the modified postgresql docker image
|
||||
`openmaptiles/postgis:6.0`. This includes the extensions `postgis` and
|
||||
`hstore`, among others, used for geospatial data processing.
|
||||
|
||||
You can try to use an external postgresql installation instead of the docker
|
||||
image, however, a lot of prequisites have to be installed into that database.
|
||||
|
||||
You can check out how the docker image is generated in [its
|
||||
repository](https://github.com/openmaptiles/openmaptiles-tools/tree/master/docker/postgis)
|
||||
and try to replicate that setup. However, this is generally not supported by
|
||||
the developers of the OpenBikeSensor portal.
|
||||
|
||||
## API
|
||||
|
||||
The API is written in Python 3 with [sanic](https://sanicframework.org/) for
|
||||
HTTP handling. It supports Python 3.6+ and comes with a list of dependencies
|
||||
that is required. One of those is `openmaptiles-tools`, which is installed from
|
||||
git (see `api/requirements.txt`). The API also depends on the `obs.face`
|
||||
package, which is included as a submodule and developed [in its own
|
||||
repository](https://github.com/openbikesensor/OpenBikeSensor-Scripts).
|
||||
|
||||
The API has the following tasks:
|
||||
|
||||
* Handle user authentication through keycloak
|
||||
* Receive track uploads and serve track data and statistics via a RESTful API
|
||||
* Process received tracks (unless using a dedicated worker, see below)
|
||||
* Publish vector tiles directly from the database (if installed and configured)
|
||||
|
||||
### Authentication
|
||||
|
||||
The frontend can redirect to `$API_URL/login` to trigger a login. The API
|
||||
negotiates a session and redirects the user agent to the keycloak instance.
|
||||
Upon successful authentication, it receives user data and generates a user
|
||||
object (or discovers the existing one) for the authenticated keycloak user.
|
||||
|
||||
A session is instanciated and kept alive through a session cookie. The API
|
||||
currently stores session data in memory, so scaling the API process to more
|
||||
replicas is not yet unsupported.
|
||||
|
||||
### RESTful API
|
||||
|
||||
There is not a lot to talk about here. The routes are pretty self explanatory,
|
||||
please refer to the code for the current API. Consider it unstable as of now.
|
||||
|
||||
There are routes for general info (version number), track and recording
|
||||
statistics (by user and time range), user management and track management.
|
||||
|
||||
### Track processing
|
||||
|
||||
If a dedicated worker is not used, the API runs the same logic as the worker
|
||||
(see below), in an asyncio "background" task. It is however *not* threaded, so
|
||||
it may block API request while processing tracks. This is the reason why a
|
||||
dedicated worker is recommended, though for a simple or low traffic setup, it
|
||||
is definitely not required. Configure whether you're using a dedicated worker
|
||||
through the `DEDICATED_WORKER` api config flag.
|
||||
|
||||
### Publish vector tiles
|
||||
|
||||
Thanks to the [OpenMapTiles](https://openmaptiles.org/) project, we're able to
|
||||
generate vector tiles from live data, directly in the PostGIS database. The
|
||||
general workflow is as follows:
|
||||
|
||||
* We have defined a schema compatible with the `openmaptiles-tools` collection
|
||||
that defines how to collect geospatial data from the postgresql database.
|
||||
This depends on its `postgis` extension for computing geospatial information
|
||||
(e.g. intersecting with a bounding box). This schema consists of a number of
|
||||
layers, which contain SQL code that is used to produce the layer's geometries
|
||||
and their attached properties.
|
||||
* The `tools/prepare_sql_tiles.py` tool calls the respective scripts from
|
||||
`openmaptiles-tools`, to compile all required SQL code into functions,
|
||||
generate the "destination" function `getmvt` for generating a vector tile,
|
||||
and store these [User-Defined
|
||||
Functions](https://www.postgresql.org/docs/current/xfunc.html) in the
|
||||
database.
|
||||
* When a tile is requested from the Map Renderer through
|
||||
`/tiles/{z}/{x}/{y}.pbf`, the API calls `getmvt` to have postgresql generate
|
||||
the tile's content on the fly, and serves the result through HTTP.
|
||||
|
||||
For all of this to work, the `openmaptiles-tools` must be installed, and the
|
||||
database has to prepared with the functions once, by use of the
|
||||
`api/tools/prepare_sql_tiles.py` script. That script should be rerun every time the
|
||||
schema changes, but doesn't need to be used if the data in the database was
|
||||
edited, e.g. by uploading and processing a new track.
|
||||
|
||||
## Frontend
|
||||
|
||||
The frontend is written in React, using Semantic UI
|
||||
([semantic-ui-react](https://react.semantic-ui.com/) and
|
||||
[semantic-ui-less](https://www.npmjs.com/package/semantic-ui-less)), compiled
|
||||
with Webpack. In a simple production setup, the frontend is compiled statically
|
||||
and served by the API.
|
||||
|
||||
The `openbikesensor-portal` image (`Dockerfile` in repo root) performs the
|
||||
build step and stores the compiled bundle and assets in
|
||||
`/opt/obs/frontend/build`. The API process can simply serve the files from there.
|
||||
|
||||
This is done with a catchall route in `obs.api.routes.frontend`, which
|
||||
determines whether to serve the `index.html` or an asset file. This ensures
|
||||
that deep URLs in the frontend receive the index file, as frontend routing is
|
||||
done in the JavaScript code by `react-router`.
|
||||
|
||||
In a development setup the frontend is served by a hot reloading development
|
||||
server (`webpack-dev-server`), compiling into memory and updating as files
|
||||
change. The frontend is then configured to communicate with the API on a
|
||||
different URL (usually a different port on localhost), which the API has to
|
||||
allow with CORS. It is configured to do so with the `FRONTEND_URL` and
|
||||
`ADDITIONAL_CORS_ORIGINS` config options.
|
||||
|
||||
### Maps in the Frontend
|
||||
|
||||
The map data is visualized using
|
||||
[maplibre-gl](https://github.com/MapLibre/maplibre-gl-js), a JavaScript library
|
||||
for rendering (vector) maps in the browser.
|
||||
|
||||
The frontend combines a basemap (for example
|
||||
[Positron](https://github.com/openmaptiles/positron-gl-style) with vector tiles
|
||||
from Mapbox or from a custom OpenMapTiles schema vector tile source) with the
|
||||
overlay data and styles. The overlay data is generated by the API
|
||||
|
||||
|
||||
## Worker
|
||||
|
||||
The Worker's job is to import the uploaded track files. The track files are
|
||||
stored as-is in the filesystem, and will usually follow the [OpenBikeSensor CSV
|
||||
Format](https://github.com/openbikesensor/OpenBikeSensorFirmware/blob/master/docs/software/firmware/csv_format.md),
|
||||
as they are generated by the measuring device.
|
||||
|
||||
The worker imports and uses the
|
||||
[`obs.face`](https://github.com/openbikesensor/OpenBikeSensor-Scripts) scripts
|
||||
to transform the data and extract the relevant events. Those are written into
|
||||
the PostgreSQL database, such that it is easy to do statistics on them and
|
||||
generate vector tiles with SQL code (see "Publish vector tiles" above).
|
||||
|
||||
|
||||
The worker determines in a loop which track to process by looking for the oldes
|
||||
unprocessed track in the database, ie. an entry in the `track` table with
|
||||
column `processing_status` set to `"queued"`. After proessing the track, the
|
||||
loop restarts after a short delay. If the worker has not found any track to
|
||||
process, the delay is longer (typically 10s), to generate less load on the
|
||||
database and CPU.
|
||||
|
||||
This means that uploading a track, within 0-10s the processing is started.
|
||||
Bulk-reprocessing is possibly by just altering the `processing_status` of all
|
||||
tracks you want to reprocess in the database directly, e.g. using the `psql`
|
||||
command line client, for example:
|
||||
|
||||
```postgresql
|
||||
UPDATE track SET processing_status = "queued" WHERE author_id = 100;
|
||||
```
|
||||
|
||||
The worker script is
|
||||
[`api/tools/process_track.py`](../api/tools/process_track.py). It has its own
|
||||
command line parser with `--help` option, and uses the `config.py` from the API
|
||||
for determining the connection to the PostgreSQL database.
|
||||
|
||||
|
||||
## Keycloak
|
||||
|
||||
The use of keycloak as an authentication provider simplifies the code of the
|
||||
portal immensely and lets us focus on actual features instead of authentication
|
||||
and its security.
|
||||
|
||||
The portal might be compatible with other OpenID Connect providers, but only
|
||||
the use of Keycloak is tested and documented. You can try to integrate with a
|
||||
different provider -- if changes to the code are needed for this, please let us
|
||||
know and/or create a Pull Request to share make the software better!
|
||||
|
||||
The keycloak configuration is rather straightforward, and it is described
|
||||
shortly for a testing setup in [README.md](../README.md).
|
||||
|
||||
For the full, secure setup, make sure to reference the Keycloak documentation
|
||||
at <https://www.keycloak.org/documentation>.
|
77
docs/licenses.md
Normal file
77
docs/licenses.md
Normal file
|
@ -0,0 +1,77 @@
|
|||
# Licenses
|
||||
|
||||
The world of software licenses is a confusing one, and you should be aware of a
|
||||
few licenses that apply to you if you use this software and its dependencies,
|
||||
or the data generated with it.
|
||||
|
||||
**Disclaimer:** This document is just an overview of things to look out for,
|
||||
and no legal advice. It may even be incorrect or incomplete. Do your own
|
||||
research or consult a professional.
|
||||
|
||||
#### Glossary
|
||||
|
||||
* OSM: [OpenStreetMap](https://openstreetmap.org)
|
||||
* OBS: [OpenBikeSensor](https://openbikesensor.org)
|
||||
* OMT: [OpenMapTiles](https://openmaptiles.org)
|
||||
|
||||
## OpenBikeSensor Portal
|
||||
|
||||
Our own software (the python packages `obs.face` and `obs.api`, the react
|
||||
frontend, the accompanying documentation, etc.) are licensed as LGPL-3.0. You
|
||||
will find the respective license files in the repositories.
|
||||
|
||||
## OpenStreetMap data
|
||||
|
||||
The moment you start importing OpenStreetMap (OSM) data into your system, its
|
||||
license applies to everything you derive from it. This usually means you'll
|
||||
have to visibly credit the OpenStreetMap contributors. Details can be found
|
||||
here: <https://www.openstreetmap.org/copyright>.
|
||||
|
||||
## OpenMapTiles project
|
||||
|
||||
The OpenMapTiles (OMT) project has a confusing multi-license setup, with different
|
||||
licenses covering the code, the schema, and the derived or generated data.
|
||||
|
||||
In any case, we're using all of that, so make sure to credit the project as
|
||||
required by their license when using the data in a different context. The
|
||||
frontend is set up to show the appropriate attributions, you should do the same
|
||||
when building a different application with the same data.
|
||||
|
||||
## Vector tiles from the API
|
||||
|
||||
These are generated using OSM data *and* OMT tools. Both have to be credited.
|
||||
Thanks to OSM being distributed under [ODbL
|
||||
1.0](https://opendatacommons.org/licenses/odbl/), you will have to distribute
|
||||
this combined data under the same license.
|
||||
|
||||
## OBS-only data exports
|
||||
|
||||
As of the writing of this document, there is no implemented export of OBS data
|
||||
(not including OSM data) from the API. We will at some point generate datasets
|
||||
of OBS data for use with other tools or to merge into a pool database, and
|
||||
these datasets will not contain OSM-licensed data, so they will have their own
|
||||
license. The portal software will not dictate the license, so as a portal
|
||||
operator, you will have to decide this for your platform, and obtain consent
|
||||
from your users to publish their uploaded data or derivatives thereof under
|
||||
your chosen license.
|
||||
|
||||
The OBS community will at some point decide on an open license for the data
|
||||
generated by the community-run portal instance(s) and pool servers, and will
|
||||
recommend the same license to all portal operators for interoperability
|
||||
reasons.
|
||||
|
||||
|
||||
## Your basemap provider
|
||||
|
||||
You have to figure out who you have to credit for the basemap you are using,
|
||||
regardless of whether you use a provider or host them yourself. In many cases,
|
||||
you will need to credit at least OpenStreetMap (for the input data) and
|
||||
OpenMapTiles (for the data scheme and tools used). If using a commercial
|
||||
provider (such as Mapbox or MapTiler), read their TOS.
|
||||
|
||||
## Code dependencies
|
||||
|
||||
Please check the licenses of our code dependencies to figure out whether they
|
||||
restrict what you can do with them. See `frontend/package.json` and
|
||||
`api/requirements.txt` for which dependencies are required for installation and
|
||||
operation.
|
Loading…
Reference in a new issue