Introduction
View Demo . Report Bug . Request Feature . Website . Sponsors . Discord . DeepWiki
PostgSail is an open-source maritime vessel tracking and data management system that automatically collects, processes, and analyzes vessel telemetry data from SignalK-compatible sources.
PostgSail is an open-source platform designed for effortless logging and historical tracking of marine vessel activity. It automatically logs voyages covering trips, anchorages, dockings, and moorages without requiring manual intervention to start or stop logging.
It's essentially a complete "digital logbook" that automatically tracks everything about your sailing adventures, from navigation to weather to vessel systems, all while providing a modern web interface for access and management.
PostgSail offers a rich set of capabilities tailored to maritime use:
- Automatic logging of voyages with details like boat speed, heading, wind speed, etc.
- Create timelapse videos of trips, with or without time control.
- Add custom notes to logs.
- Export logs in various formats: CSV, GPX, GeoJSON, KML, PNG, MP4.
- Trip statistics and aggregations: longest voyage, time spent anchored, home ports, etc.
- Visualize moorages on a global map, showing incoming/outgoing voyages.
- Remote monitoring of metrics—position, depth, wind, temperature, battery, etc.
- Trend history and alert notifications (via email, PushOver, or Telegram) for conditions like low voltage or low fuel.
- Support for offline and low-bandwidth operation.
- Integration with monitoring dashboards using Grafana and related tools.
Deployment
PostgSail supports both cloud-hosted and self-hosted deployment options:
Cloud-based SaaS iot.openplotter.cloud
- Managed PostgreSQL
- Managed infrastructure
- Automatic scaling and backup
- Free for single vessel use
- Multi-vessel commercial plans available
- Generate video(s) of trip(s)
- Generate image(s) of trip(s)
- AI assistant
- Image gallery support
Self-Hosted (Infrastructure you manage)
- Docker Compose orchestration
- Full control over data and configuration
- Requires Docker and basic Linux administration
- Requires PostgreSQL administration
- Custom integration capabilities
Cloud-hosted PostgSail
Remove the hassle of running PostgSail yourself. Here you can skip the technical setup, the maintenance work and server costs by getting PostgSail on our reliable and secure PostgSail Cloud. Register and try for free at iot.openplotter.cloud.
PostgSail Cloud is Open Source and free for personal use with a single vessel. If wish to manage multiple boats contact us.
PostgSail is free to use, but is not free to make or host. The stability and accuracy of PostgSail depends on its volunteers and donations from its users. Please consider sponsoring PostgSail.
Infrastructure you manage
Self host postgSail where you want and how you want. There are no restrictions, you’re in full control. Install Guide
PostgSail is free to use, but is not free to make or host. The stability and accuracy of PostgSail depends on its volunteers and donations from its users. Please consider sponsoring PostgSail.
Self-Hosting the PostgSail Control Plane
Self-hosting PostgSail means running your own instance of the PostgSail Control Plane.
When you self-host PostgSail, you’re deploying:
- Database (backend) - PostgreSQL for storing state and metadata
- API Server - REST APIs using PostgREST
- Dashboard (frontend) - Web UI for monitoring and visualize logs,stays,moorages
Setup & Deployment
Architecture
Efficient, simple and scalable architecture.
flowchart TD
%% User
user([User])
%% Frontend and Auth
user -->|HTTPS| frontend[Frontend VueJS]
user -->|HTTPS| grafana[Grafana]
%% Web Server Layer
frontend -->|Apache / nginx| postgrest[PostgREST]
%% Database
postgrest --> |SQL|postgres[(PostgreSQL / TimescaleDB / PostGIS / MobilityDB)]
grafana --> |SQL|postgres
%% External System
postgres -->|HTTPS|telegram[Telegram API]
postgres -->|HTTPS|pushover[Pushover API]
postgres -->|SMTP|email[Email]
postgres -->|HTTPS|overpass[Overpass API]
postgres -->|HTTPS|nominatim[Nominatim Geocoding]
%% Boat (External Client)
vessel([Boat])
vessel -->|HTTPS| postgrest
%% MCP (External Client)
mcp([AI-Agent])
mcp -->|HTTPS| postgrest
%% Telegram Bot (External Client)
telegram_bot([Telegram Bot])
telegram_bot -->|HTTPS| postgrest
%% Groupings
subgraph Clients
user
vessel
mcp
telegram_bot
end
subgraph PostgSail
frontend
grafana
postgrest
postgres
end
subgraph "Notification endpoint"
telegram
pushover
email
end
subgraph "Data endpoint"
overpass
nominatim
end
For more clarity and visibility the complete Entity-Relationship Diagram (ERD) is export as Mermaid file.
Using PostgSail
On-premise (self-hosted)
This deployment needs the docker application to be installed and running. Check this tutorial.
Docker run pre packaged application (aka images) which can be retrieved as sources (Dockerfile and resources) to build or already built from registries (private or public).
PostgSail depends heavily on PostgreSQL. Check this tutorial.
pre-deploy configuration
To get these running, copy .env.example and rename to .env then set the value accordingly.
# cp .env.example .env
# nano .env
Notice, that PGRST_JWT_SECRET must be at least 32 characters long.
$ cat /dev/urandom | LC_ALL=C tr -dc 'a-zA-Z0-9' | fold -w 42 | head -n 1
PGSAIL_APP_URL is the URL you connect to from your browser.
PGSAIL_API_URL is the URL where PGSAIL_APP_URL connect to.
PGRST_DB_URI is the URI where the PGSAIL_API_URL connect to.
For more details check the Environment Variables.
To summarize:
flowchart LR
subgraph frontend
direction TB
A(PGSAIL_APP_URL)
B(PGSAIL_API_URL)
end
subgraph backend
direction TB
B(PGSAIL_API_URL) -- SQL --> C(PGRST_DB_URI)
end
%% ^ These subgraphs are identical, except for the links to them:
%% Link *to* subgraph1: subgraph1 direction is maintained
User -- HTTP --> A
User -- HTTP --> B
%% Link *within* subgraph2:
%% subgraph2 inherits the direction of the top-level graph (LR)
Boat -- HTTP --> B
Deploy
There is two compose files used. You can update the default settings by editing docker-compose.yml and docker-compose.dev.yml to your need.
Now let’s initialize the database.
Step 1. Initialize database
First let’s import the SQL schema, execute:
$ docker compose up db
Step 2. Start backend (db, api)
Then launch the full backend stack (db, api), execute:
$ docker compose up db api
The API should be accessible via port HTTP/3000. The database should be accessible via port TCP/5432.
You can connect to the database via a web gui like pgadmin or you can use a client dbeaver.
$ docker compose -f docker-compose.yml -f docker-compose.dev.yml pgadmin
Then connect to the web UI on port HTTP/5050.
Step 3. Start frontend (web)
Last build and launch the web frontend, execute:
docker compose build web
docker compose up web
The first step can take some time as it will first run a build to generate the static website based on your settings.
The frontend is a SPA (Single-Page Application). With SPA, the server provides the user with an empty HTML page and Javascript. The latter is where the magic happens. When the browser receives the HTML + Javascript, it loads the Javascript. Once loaded, the JS takes place and, through a set of operations in the DOM, renders the necessary components to the page. The routing is then handled by the browser itself, not hitting the server.
The frontend should be accessible via port HTTP/8080.
Users are collaborating on two installation guide:
- Self-hosted-installation-guide
- Self-hosted-installation-guide on AWS EC2
- Self-hosted-installation-guide
SQL Configuration
Check and update your postgsail settings via SQL in the table app_settings:
SELECT * FROM app_settings;
UPDATE app_settings
SET
value = 'new_value'
WHERE name = 'app.email_server';
As it is all about SQL, Read more about the database to configure your instance and explore your data.
Ingest data
Next, to ingest data from signalk, you need to install signalk-postgsail plugin on your signalk server instance.
Also, if you like, you can import saillogger data using the postgsail helpers, postgsail-helpers.
You might want to import your influxdb1 data as well, outflux. For InfluxDB 2.x and 3.x. You will need to enable the 1.x APIs to use them. Consult the InfluxDB documentation for more details.
Last, if you like, you can import the sample data from Signalk NMEA Plaka by running the tests. If everything goes well all tests pass successfully and you should receive a few notifications by email or PushOver or Telegram. End-to-End (E2E) Testing.
$ docker-compose up tests
API Documentation
The OpenAPI description output depends on the permissions of the role that is contained in the JWT role claim.
Other applications can also use the PostgSAIL API.
API anonymous:
$ curl http://localhost:3000/
API user_role:
$ curl http://localhost:3000/ -H 'Authorization: Bearer my_token_from_login_or_signup_fn'
API vessel_role:
$ curl http://localhost:3000/ -H 'Authorization: Bearer my_token_from_register_vessel_fn'
API main workflow
Check the End-to-End (E2E) test sample.
Docker dependencies
docker compose is used to start environment dependencies. Dependencies consist of 3 containers:
timescaledb-postgisaliasdb, PostgreSQL with TimescaleDB extension along with the PostGIS extension.postgrestaliasapi, Standalone web server that turns your PostgreSQL database directly into a RESTful API.grafanaaliasapp, visualize and monitor your data
Optional docker images
- pgAdmin, web UI to monitor and manage multiple PostgreSQL
- Swagger, web UI to visualize documentation from PostgREST
docker-compose -f docker-compose-optional.yml up
Environment Variables
Environment Variables
You need to configure PostgSail using environment variables. Copy the example file.
cp .env.example .env
Environment Variables Documentation
This document describes all environment variables used in the PostgSail system, organized by category and usage context.
Database Configuration
| Environment Variable | Example | Description |
|---|---|---|
POSTGRES_USER | postgres | PostgreSQL superuser username for database administration |
POSTGRES_PASSWORD | changeme | Password for the PostgreSQL superuser for database administration |
PGSAIL_AUTHENTICATOR_PASSWORD | generated_password | Password for the PostgREST authenticator role |
API Configuration
| Environment Variable | Example | Description |
|---|---|---|
PGRST_JWT_SECRET | generated_secret_min_32_chars | JWT secret for PostgREST authentication (minimum 32 characters) |
PGSAIL_API_URL | http://localhost:3000 or https://api.example.com | Base URL for the PostgSail API endpoint, API entrypoint from the webapp |
Frontend Configuration
| Environment Variable | Example | Description |
|---|---|---|
VITE_APP_TITLE | PostgSail | Application title displayed in the frontend |
VITE_PGSAIL_URL | ${PGSAIL_API_URL} | API URL used by the Vue.js frontend, same as ${PGSAIL_API_URL} |
VITE_GRAFANA_URL | http://localhost:3001 or https://grafana.example.com | Grafana dashboard URL for frontend integration |
Grafana Configuration
| Environment Variable | Example | Description |
|---|---|---|
PGSAIL_GRAFANA_PASSWORD | admin_password | Admin password for Grafana dashboard access |
External Integrations
| Environment Variable | Example | Description |
|---|---|---|
PGSAIL_TELEGRAM_BOT_TOKEN | bot_token_from_botfather | Telegram bot token for notifications |
PGSAIL_EMAIL_SERVER | smtp.example.com | SMTP server for email notifications |
PGSAIL_EMAIL_USER | notifications@example.com | Email username for SMTP authentication |
PGSAIL_EMAIL_PASS | email_password | Email password for SMTP authentication |
PGSAIL_EMAIL_FROM | PostgSail <noreply@example.com> | From address for outgoing emails |
Push Notifications
| Environment Variable | Example | Description |
|---|---|---|
PGSAIL_PUSHOVER_APP_TOKEN | pushover_token | Pushover application token for push notifications |
PGSAIL_PUSHOVER_APP_URL | https://pushover.net/subscribe/qwerty | Pushover subscribe endpoint URL |
Development Tools
| Environment Variable | Example | Description |
|---|---|---|
PGADMIN_DEFAULT_EMAIL | admin@example.com | Default email for pgAdmin web interface |
PGADMIN_DEFAULT_PASSWORD | admin_password | Default password for pgAdmin access |
Additional Services
| Environment Variable | Example | Description |
|---|---|---|
PGSAIL_APP_URL | http://localhost:8080 or http://www.example.com | Main application URL |
Additional parameters are directly set in the docker-compose.yml
SignalK PostgSail plugin
SignalK server plugin to send all self SignalK numeric data and navigation entry to a PostgSail server.
Send, monitor, alert, observe all numeric values & positions & status to a self-hosted or cloud instances of PostgSail (PostgreSQL, Grafana).
Dependencies
signalk-autostate by @meri-imperiumi. Used to determine the vessel’s state based on sensor values, and updates the navigation.state value accordingly.
The signalk-derived-data and signalk-path-mapper plugins are both useful to remap available data to the required canonical paths.
Source data
| SignalK path | Timeline name | Notes |
|---|---|---|
navigation.state | use for trip start/end and motoring vs sailing | |
navigation.courseOverGroundTrue | Course | |
navigation.headingTrue | Heading | |
navigation.speedThroughWater | ||
navigation.speedOverGround | Speed | |
environment.wind.directionTrue | Wind | |
environment.wind.speedTrue | Wind | |
environment.wind.speedOverGround | Wind | |
environment.*.pressure | Baro | Pressure in zone |
environment.*.temperature | Temp | |
environment.*.relativeHumidity | Ratio | 1 = 100% |
environment.water.swell.state | Sea | |
navigation.position | Coordinates | |
navigation.log | Log | If present, used to calculate distance |
propulsion.*.runTime | Engine | If present, used to calculate engine hour usage |
steering.autopilot.state | Autopilot changes are logged. | |
navigation.state | If present, used to start and stop automated hourly entries. Changes are logged. | |
propulsion.*.state | Propulsion changes are logged. | |
electrical.batteries.*.voltage | Voltage measured | |
electrical.batteries.*.current | Current measured | |
electrical.batteries.*.stateOfCharge | ratio | State of charge, 1 = 100% |
electrical.solar.* | Solar measured | |
tanks.*.currentLevel | Level of fluid in tank 0-100% | |
tanks.*.capacity.* | Total capacity |
The signalk-derived-data and signalk-path-mapper plugins are both useful to remap available data to the required canonical paths.
Hosting Environment–specific Guides
Docker
Connect to the server
% ssh root@my.server.com
Clone the git repo
% git clone https://github.com/xbgmsharp/postgsail
Cloning into 'postgsail'...
...
Edit the configuration
% cd postgsail
% cp .env.example .env
% cat /dev/urandom | LC_ALL=C tr -dc 'a-zA-Z0-9' | fold -w 42 | head -n 1
..
% nano .env
Install Docker
From https://docs.docker.com/engine/install/ubuntu/
% apt-get update
...
% apt-get install -y ca-certificates curl
...
% install -m 0755 -d /etc/apt/keyrings
% curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
% chmod a+r /etc/apt/keyrings/docker.asc
% echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \
$(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
% apt-get update
...
% apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
...
Init the database
% docker compose up db
...
Gracefully stopping... (press Ctrl+C again to force)
[+] Stopping 1/1
✔ Container db Stopped
Start the db with the api
% docker compose pull api
...
% docker compose up -d db api
Checks
Making sure it works.
% telnet localhost 5432
...
telnet> quit
Connection closed.
% curl localhost:3000
...
% docker ps
...
% docker logs api
...
Run the web instance
% docker compose -f docker-compose.yml -f docker-compose.dev.yml build web (be patient)
...
% docker compose -f docker-compose.yml -f docker-compose.dev.yml up web (be patient)
...
web |
web | ➜ Local: http://localhost:8080/
web | ➜ Network: http://172.18.0.4:8080/
Docker Compose
Running with Docker Compose
You can use example docker-compose.yml
file as a reference
services:
martin:
image: ghcr.io/maplibre/martin:v0.16.0
restart: unless-stopped
ports:
- "3000:3000"
environment:
- DATABASE_URL=postgresql://postgres:password@db/db
depends_on:
- db
db:
image: postgis/postgis:17-3.5-alpine
restart: unless-stopped
environment:
- POSTGRES_DB=db
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=password
volumes:
# persist PostgreSQL data in a local directory outside of the docker container
- ./pg_data:/var/lib/postgresql/data
First, you need to start db service
docker compose up -d db
Then, after db service is ready to accept connections, you can start martin
docker compose up -d martin
By default, Martin will be available at localhost:3000
Official Docker image includes a HEALTHCHECK instruction which will be used by Docker Compose. Note that Compose won’t restart unhealthy containers. To monitor and restart unhealthy containers you can use Docker Autoheal.
AWS
Self AWS cloud hosted setup example
In this guide we install, setup and run a postgsail project on an AWS instance in the cloud.
On AWS Console
Launch an instance on AWS EC2 With the following settings:
-
Ubuntu
-
Instance type: t2.small
-
Create a new key pair:
- key pair type: RSA
- Private key file format: .pem
-
The key file is stored for later use
-
Allow SSH traffic from: Anywhere
-
Allow HTTPS traffic from the internet
-
Allow HTTP traffic from the internet
Configure storage: The standard storage of 8GiB is too small so change this to 16GiB.
Create a new security group
- Go to: EC2>Security groups>Create security group Add inbound rules for the following ports:443, 8080, 80, 3000, 5432, 22, 5050
- Go to your instance>select your instance>Actions>security>change security group
- And add the correct security group to the instance.
Connect to instance with SSH
- Copy the key file in your default SSH configuration file location (the one VSCode will use)
- In terminal, go to the folder and run this command to ensure your key is not publicly viewable:
chmod 600 "privatekey.pem"
We are using VSCode to connect to the instance:
- Install the Remote - SSH Extension for VSCode
- Open the Command Palette (Ctrl+Shift+P) and type Remote-SSH: Add New SSH Host:
ssh -i "privatekey.pem" ubuntu@ec2-111-22-33-44.eu-west-1.compute.amazonaws.com
When prompted, select the default SSH configuration file location. Open the config file and add the location:
xIdentityFile ~/.ssh/privatekey.pem
Install Docker on your instance
To install Docker on your new EC2 Ubuntu instance via SSH, follow these steps:
Update your package list:
sudo apt-get update
Install required dependencies:
sudo apt-get install apt-transport-https ca-certificates curl software-properties-common
Add Docker’s official GPG key:
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
Add Docker’s official repository:
echo "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
Update the package list again:
sudo apt-get update
Install Docker:
sudo apt-get install docker-ce docker-ce-cli containerd.io
Verify Docker installation:
sudo docker --version
Add your user to the docker group to run Docker without sudo:
sudo usermod -aG docker ubuntu
Then, log out and back in or use the following to apply the changes:
newgrp docker
Now you can follow the Postgsail process.
Reverse Proxies
PostgSail can run without a reverse proxy. Hosting PostgSail behind a reverse proxy can help with security, scalability, and flexibility.
Doing so has a few downsides:
- PostgSail does not support HTTPS connections (TLS termination).
- We do not check
HOST-headers - we just serve on a port. This means anybody can point their dns record to your server and serve to all requests going to the port Martin is running on. Using a reverse proxy makes this abuse obvious. - Martin only supports a simple in-memory caching. If you need more advanced caching options, you can use a reverse proxy like Nginx, Varnish, or Apache with custom rules. For example, you may choose to only cache zoom 0..10.
- You may need to host more than just tiles at a single domain name.
NGINX
Using with NGINX
You should run PostgSail behind NGINX proxy, so you can cache frequently accessed tiles and reduce unnecessary pressure on the database. Here is an example docker-compose.yml file that runs PostgSail with NGINX and PostgreSQL.
version: '3'
services:
nginx:
image: nginx:alpine
restart: unless-stopped
ports:
- "80:80"
volumes:
- ./cache:/var/cache/nginx
- ./nginx.conf:/etc/nginx/nginx.conf:ro
depends_on:
- martin
martin:
image: maplibre/martin:v0.7.0
restart: unless-stopped
environment:
- DATABASE_URL=postgresql://postgres:password@db/db
depends_on:
- db
db:
image: postgis/postgis:14-3.3-alpine
restart: unless-stopped
environment:
- POSTGRES_DB=db
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=password
volumes:
- ./pg_data:/var/lib/postgresql/data
You can find an example NGINX configuration file here.
Rewriting URLs
If you are running Martin behind NGINX proxy, you may want to rewrite the request URL to properly handle tile URLs in TileJSON.
location ~ /tiles/(?<fwd_path>.*) {
proxy_set_header X-Rewrite-URL $uri;
proxy_set_header X-Forwarded-Host $host:$server_port;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_redirect off;
proxy_pass http://martin:3000/$fwd_path$is_args$args;
}
Caching tiles
You can also use NGINX to cache tiles. In the example, the maximum cache size is set to 10GB, and caching time is set to 1 hour for responses with codes 200, 204, and 302 and 1 minute for responses with code 404.
http {
...
proxy_cache_path /var/cache/nginx/
levels=1:2
max_size=10g
use_temp_path=off
keys_zone=tiles_cache:10m;
server {
...
location ~ /tiles/(?<fwd_path>.*) {
proxy_set_header X-Rewrite-URL $uri;
proxy_set_header X-Forwarded-Host $host:$server_port;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_redirect off;
proxy_cache tiles_cache;
proxy_cache_lock on;
proxy_cache_revalidate on;
# Set caching time for responses
proxy_cache_valid 200 204 302 1h;
proxy_cache_valid 404 1m;
proxy_cache_use_stale error timeout http_500 http_502 http_503 http_504;
add_header X-Cache-Status $upstream_cache_status;
proxy_pass http://martin:3000/$fwd_path$is_args$args;
}
}
}
You can find an example NGINX configuration file here.
Apache
Using with Apache
You should run PostgSail behind Apache “kind of” proxy, so you can use HTTPs with it. Here is an example of the configuration file that runs PostgSail with Apache.
First you have to setup a virtual host that is working on the port 443.
Enable necessary modules
Ensure the required modules are enabled:
sudo a2enmod proxy
sudo a2enmod proxy_http
sudo a2enmod headers
sudo a2enmod rewrite
Modify your VHOST configuration
Open your VHOST configuration file for the domaine you’re using, mydomain.tld :
sudo nano /etc/apache2/sites-available/mydomain.tld.conf
Update the configuration
<VirtualHost *:443>
ServerName mydomain.tld
ServerAdmin webmaster@localhost
DocumentRoot /var/www/mydomain
ProxyPreserveHost On
RewriteEngine on
RewriteCond %{REQUEST_URI} ^/tiles/(.*)$
RewriteRule ^/tiles/(.*)$ http://localhost:3000/tiles/$1 [P,L]
<IfModule mod_headers.c>
RequestHeader set X-Forwarded-Proto "https"
</IfModule>
ProxyPass / http://localhost:3000/
ProxyPassReverse / http://localhost:3000/
</VirtualHost>
Check Configuration: Verify the Apache configuration for syntax errors
sudo apache2ctl configtest
Restart Apache: If the configuration is correct, restart Apache to apply the changes
sudo systemctl restart apache2
Upgrade
Containers
docker compose pull
Self hosted upgrade guide
In this guide we are updating a self hosted installation version 0.7.2 to version 0.9.3. When updating from or to other versions principle remain the same.
The installation we are upgrading was installed in April 2024 using the installation instructions found on the pgsail github site. Platform is an Ubuntu 22.04 Virtual Machine. Before the upgrade, around 120 trips were logged. Needless to say we don’t want to loose our data.
Unfortunately, there is no automatic update path available, this may change but for now we had to follow the general update instructions.
General update instructions
- Stop the containers.
- Make a backup
- Update the containers.
- Update possible database extensions.
- Run database migrations.
- Additional data migration.
- Update SignalK client.
Let’s go
Tools used
In addition to the tools that are already installed as part of Ubuntu and PostgSail, I used DBeaver to examine the database from my Windows desktop.
Make a backup
Start by making a backup of the database, the docker-compose.yml and .env files. Note that in my case the database was stored in a host folder, later versions are using a docker volume. To copy the database it necessary the containers are stopped.
cd postgsail
mkdir backup
docker compose stop
cp .env docker-compose.yml backup/
docker compose cp -a db:/var/lib/postgresql/data backup/db-data
Update the containers
Make a note of the last migration in the initdb folder, in my case this was 99_migrations_202404.sql. Because I used git clone, the migration file was a bit in between 0.7.1 and 0.7.2, therefore I decided 99_migrations_202404.sql was the first migration to run.
Remove the containers:
docker compose down
Get the latest PostgSail from github, we checkout a specific tag to ensure we have a stable release version. If you installed it from a binary release, just update from the latest binary release.
git pull remote main
git fetch --all --tags
git checkout tags/v0.9.3
Note: switching to 'tags/v0.9.3'.
You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by switching back to a branch.
If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -c with the switch command. Example:
git switch -c <new-branch-name>
Or undo this operation with:
git switch -
Turn off this advice by setting config variable advice.detachedHead to false
HEAD is now at 12e4baf Release PostgSail 0.9.3
Ensure new docker-compose.yml file matches your database folder or volume setting, adjust as needed.
Get the latest containers.
docker compose pull
Update possible extensions
Start database container.
docker compose up -d db
Execute psql shell in database container.
docker compose exec db sh
psql --username "$POSTGRES_USER" --dbname "$POSTGRES_DB"
\c signalk;
Check extensions which can be updated, be sure to run from the signalk database:
SELECT name, default_version, installed_version FROM pg_available_extensions where default_version <> installed_version;
The postgis extension can be upgraded with this SQL query:
SELECT postgis_extensions_upgrade();
Updating the timescaledb requires running from a new session, use following commands (note the -X options, that is necessary):
docker compose exec db sh
psql --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" -X
Then run following SQL commands from the psql shell:
ALTER EXTENSION timescaledb UPDATE;
CREATE EXTENSION IF NOT EXISTS timescaledb_toolkit;
ALTER EXTENSION timescaledb_toolkit UPDATE;
For others, to be checked. In my case, the postgis extension was essential.
Vacuum tables
It’s necessary to do VACUUM periodically, especially on frequently-updated tables.
garbage-collect and optionally analyze a database
docker compose exec db sh
psql --username "$POSTGRES_USER" --dbname "$POSTGRES_DB"
\c signalk;
This operations may take some time and does require exclusive lock.
VACUUM (FULL, VERBOSE, ANALYZE, INDEX_CLEANUP) public.process_queue,public.app_settings,public.email_templates;
VACUUM (FULL, VERBOSE, ANALYZE, INDEX_CLEANUP) auth.accounts,auth.vessels,auth.otp;
VACUUM (FULL, VERBOSE, ANALYZE, INDEX_CLEANUP) api.logbook,api.stays,api.moorages,api.metadata,api.metrics;
Run database migrations
Then run the migrations, adjust start and end for first and last migration file to execute.
start=202404; end=202507; for f in $(ls ./docker-entrypoint-initdb.d/99_migrations_*.sql | sort); do s=$(basename "$f" | sed -E 's/^99_migrations_([0-9]{6})\.sql$/\1/'); if [[ "$s" < "$start" || "$s" > "$end" ]]; then continue; fi; echo "Running $f"; psql --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" < "$f"; done
Or line by line
psql --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" < ./docker-entrypoint-initdb.d/99_migrations_202404.sql
psql --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" < ./docker-entrypoint-initdb.d/99_migrations_202405.sql
psql --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" < ./docker-entrypoint-initdb.d/99_migrations_202406.sql
psql --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" < ./docker-entrypoint-initdb.d/99_migrations_202407.sql
psql --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" < ./docker-entrypoint-initdb.d/99_migrations_202408.sql
psql --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" < ./docker-entrypoint-initdb.d/99_migrations_202409.sql
psql --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" < ./docker-entrypoint-initdb.d/99_migrations_202410.sql
psql --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" < ./docker-entrypoint-initdb.d/99_migrations_202411.sql
psql --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" < ./docker-entrypoint-initdb.d/99_migrations_202412.sql
psql --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" < ./docker-entrypoint-initdb.d/99_migrations_202501.sql
psql --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" < ./docker-entrypoint-initdb.d/99_migrations_202504.sql
psql --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" < ./docker-entrypoint-initdb.d/99_migrations_202505.sql
psql --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" < ./docker-entrypoint-initdb.d/99_migrations_202507.sql
Now rebuild the web app.
docker compose build web
Maybe need to run 99env.sh - check.
Then we can start the other containers.
docker compose up -d
After everything is started, the web site should be accessible.
Additional data migration
Depending on the starting version, additional data migration may be needed. If the old trips are visible, but the routes are not, we need to run an SQL Script to re-calculate the trip metadata.
DO $$
declare
-- Re calculate the trip metadata
logbook_rec record;
avg_rec record;
t_rec record;
begin
FOR logbook_rec IN
SELECT *
FROM api.logbook
WHERE _from IS NOT NULL
AND _to IS NOT NULL
AND active IS FALSE
AND trip IS NULL
--AND trip_heading IS NULL
--AND vessel_id = '06b6d311ccfe'
ORDER BY id DESC
LOOP
-- Update logbook entry with the latest metric data and calculate data
PERFORM set_config('vessel.id', logbook_rec.vessel_id, false);
-- Calculate trip metadata
avg_rec := logbook_update_avg_fn(logbook_rec.id, logbook_rec._from_time::TEXT, logbook_rec._to_time::TEXT);
--UPDATE api.logbook
-- SET extra = jsonb_recursive_merge(extra, jsonb_build_object('avg_wind_speed', avg_rec.avg_wind_speed))
-- WHERE id = logbook_rec.id;
if avg_rec.count_metric IS NULL OR avg_rec.count_metric = 0 then
-- We don't have the orignal metrics, we should read the geojson
continue; -- return current row of SELECT
end if;
-- mobilitydb, add spaciotemporal sequence
-- reduce the numbers of metrics by skipping row or aggregate time-series
-- By default the signalk plugin report one entry every minute.
IF avg_rec.count_metric < 30 THEN -- if less ~20min trip we keep it all data
t_rec := logbook_update_metrics_short_fn(avg_rec.count_metric, logbook_rec._from_time, logbook_rec._to_time);
ELSIF avg_rec.count_metric < 2000 THEN -- if less ~33h trip we skip data
t_rec := logbook_update_metrics_fn(avg_rec.count_metric, logbook_rec._from_time, logbook_rec._to_time);
ELSE -- As we have too many data, we time-series aggregate data
t_rec := logbook_update_metrics_timebucket_fn(avg_rec.count_metric, logbook_rec._from_time, logbook_rec._to_time);
END IF;
--RAISE NOTICE 'mobilitydb [%]', t_rec;
IF t_rec.trajectory IS NULL THEN
RAISE WARNING '-> process_logbook_queue_fn, vessel_id [%], invalid mobilitydb data [%] [%]', logbook_rec.vessel_id, _id, t_rec;
RETURN;
END IF;
RAISE NOTICE '-> process_logbook_queue_fn, vessel_id [%], update entry logbook id:[%] start:[%] end:[%]', logbook_rec.vessel_id, logbook_rec.id, logbook_rec._from_time, logbook_rec._to_time;
UPDATE api.logbook
SET
trip = t_rec.trajectory,
trip_cog = t_rec.courseovergroundtrue,
trip_sog = t_rec.speedoverground,
trip_twa = t_rec.windspeedapparent,
trip_tws = t_rec.truewindspeed,
trip_twd = t_rec.truewinddirection,
trip_notes = t_rec.notes, -- don't overwrite existing user notes. **** Must set trip_notes otherwise replay is not working.
trip_status = t_rec.status,
trip_depth = t_rec.depth,
trip_batt_charge = t_rec.stateofcharge,
trip_batt_voltage = t_rec.voltage,
trip_temp_water = t_rec.watertemperature,
trip_temp_out = t_rec.outsidetemperature,
trip_pres_out = t_rec.outsidepressure,
trip_hum_out = t_rec.outsidehumidity,
trip_heading = t_rec.heading, -- heading True
trip_tank_level = t_rec.tankLevel, -- Tank currentLevel
trip_solar_voltage = t_rec.solarVoltage, -- solar voltage
trip_solar_power = t_rec.solarPower -- solar powerPanel
WHERE id = logbook_rec.id;
END LOOP;
END $$;
Update SignalK client
The SignalK client can be updated from the SignalK Web UI. After the migration we updated this to version v0.5.0
Trouble shooting
During this migration, several issues came up, they eventually boiled down to an extension not updated and permissions issues.
Postgres
List postgres extensions:
SELECT e.extname AS "Name", e.extversion AS "Version", n.nspname AS "Schema", c.description AS "Description"
FROM pg_catalog.pg_extension e
LEFT JOIN pg_catalog.pg_namespace n ON n.oid = e.extnamespace
LEFT JOIN pg_catalog.pg_description c ON c.objoid = e.oid AND c.classoid = 'pg_catalog.pg_extension'::pg_catalog.regclass
ORDER BY 1;
List installed extensions available for upgrade
SELECT name, default_version, installed_version FROM pg_available_extensions where default_version <> installed_version;
Troubleshooting
Model context protocol (MCP)
Connect your AI tools to PostgSail using MCP
The Model Context Protocol (MCP) is a standard for connecting Large Language Models (LLMs) to platforms like PostgSail.
Once connected, your AI assistants can interact with and query your PostgSail API on your behalf.
PostgSail MCP server provides AI agents with read-only access to PostgSail marine data systems. This server enables LeChat, Claude and other AI assistants to search and navigate logs, moorages, and stays, monitor and analyze your boat all in one place.
Key Features
- Daily vessel summaries (current status, weather, systems)
- Voyage summary (reviewing past trips, moorages, stays information)
- System monitoring (battery, solar, sensors, connectivity)
- Historical analysis (tracking patterns, favorite destinations)
- Data export (for external navigation tools)
- Maintenance tracking (through stay notes and logs)
Authentication
Tool execution (API call) require a valid PostgSail JWT token. Get your token from the profile settings page in the web portal.
Available Methods
MCP implementation:
- initialize - Initialize MCP connection
- tools/list - List available tools
- tools/call - Execute a tool (requires JWT authentication)
- prompts/list - List available prompts
- prompts/get - Get a specific prompt
- resources/list - List available resources
- resources/read - Read a specific resource
Remote MCP Server
Accessible at https://mcp.openplotter.cloud/
LeChat allow remote connectors even with a free account.
Others AI ClaudeAI and OpenAI requires an upgrade plan to use remote connectors.
However you can use the MCP locally with Claude Desktop app.
Endpoints
POST /mcp - Main MCP endpoint (JSON-RPC 2.0)
GET /health - Health check endpoint
GET / - Overview
Authentication
The authentication is done via authorization Bearer header, https://iot.openplotter.cloud/profile profile page -> MCP.
Configuration
{
"mcpServers": {
"postgsail": {
"type": "streamable-http",
"url": "https://mcp.openplotter.cloud/mcp",
"note": "A Model Context Protocol (MCP) server that provides AI agents with read-only access to PostgSail marine data systems.",
"headers": {
"Authorization": "Bearer ${POSTGSAIL_MCP_ACCESS_TOKEN}"
}
}
}
}
Local STDIO MCP Server
Accessible locally, works with Claude Desktop app.
Installation
- Install Claude App
- Settings -> Extensions
- Drag .MCPB or .DXT files here to install
OR
- Install Claude App.
- Settings -> Extensions -> Advanced settings -> Extension Developer
- Install Extension…
API Documentation
Overview
PostgSail exposes its PostgreSQL database through a RESTful API using PostgREST, which serves as the primary interface for all client interactions. The API supports three main authentication roles that determine access permissions and available endpoints.
Authentication
The API uses JWT (JSON Web Token) authentication with role-based switching. The JWT token contains claims that set session variables used by Row Level Security policies:
vessel.id- Current vessel identifieruser.email- Current user emailuser.id- Current user identifier
API Roles
api_anonymous
Unauthenticated access with read-only permissions on public data for public access when enable
user_role
Authenticated web users with full access to their vessel data.
vessel_role
SignalK plugin data ingestion with insert/update permissions.
mcp_role
Authenticated web users with read-only access to their vessel data via an Large language model.
API Endpoints
Base URL
http://localhost:3000
Authentication Examples
Anonymous access:
curl http://localhost:3000/
User role access:
curl http://localhost:3000/ -H 'Authorization: Bearer my_token_from_login_or_signup_fn'
Vessel role access:
curl http://localhost:3000/ -H 'Authorization: Bearer my_token_from_register_vessel_fn'
Key Endpoints by Role
Authentication Functions
POST /rpc/login- User authenticationPOST /rpc/signup- User registrationPOST /rpc/register_vessel- Vessel registration
Data Tables (user_role and vessel_role)
GET /metrics- Time-series telemetry dataGET /logbook- Trip records with trajectoriesGET /stays- Mooring/anchoring periodsGET /moorages- Named locationsGET /metadata- Vessel metadata including configuration
Views (user_role)
GET /logs_view- Enriched logbook dataGET /log_view- Details logbook dataGET /moorages_view- Enriched moorage dataGET /moorage_view- Details moorage dataGET /stays_view- Enriched Stays dataGET /stay_view- Details Stay dataGET /vessels_view- Vessel dataGET /monitoring_view- System monitoring data
RPC Functions
POST /rpc/settings_fn- User preferencesPOST /rpc/update_user_preferences_fn- Update preferencesPOST /rpc/versions_fn- System version informationPOST /rpc/vessel_fn- Vessel details
OpenAPI Documentation
The OpenAPI specification is dynamically generated based on the authenticated role’s permissions. Access the interactive documentation at:
https://petstore.swagger.io/?url=https://raw.githubusercontent.com/xbgmsharp/postgsail/main/openapi.json
Other applications can also use the PostgSAIL API.
The available endpoints and operations in the OpenAPI spec will vary depending on the JWT role used to access /.
Public Access
Anonymous users can access specific public data when vessel owners have enabled public sharing.
Configuration
The PostgREST service is configured via environment variables:
PGRST_DB_SCHEMA: api- Default schemaPGRST_DB_ANON_ROLE: api_anonymous- Anonymous rolePGRST_DB_PRE_REQUEST: public.check_jwt- JWT validation functionPGRST_JWT_SECRET- JWT signing secret
Notes
- The API runs on port 3000 by default
- All data access is controlled by Row Level Security policies based on vessel ownership
- The SignalK plugin uses vessel_role for continuous data ingestion
- Rate limiting and connection limits are enforced per role
ERD Schema
erDiagram
api_logbook {
text _from "Name of the location where the log started, usually a moorage name"
double_precision _from_lat
double_precision _from_lng
integer _from_moorage_id "Link api.moorages with api.logbook via FOREIGN KEY and REFERENCES"
timestamp_with_time_zone _from_time "{NOT_NULL}"
text _to "Name of the location where the log ended, usually a moorage name"
double_precision _to_lat
double_precision _to_lng
integer _to_moorage_id "Link api.moorages with api.logbook via FOREIGN KEY and REFERENCES"
timestamp_with_time_zone _to_time
boolean active
double_precision avg_speed "avg speed in knots"
numeric distance "Distance in Nautical Miles converted mobilitydb meters to NM"
interval duration "Duration in ISO 8601 format"
jsonb extra "Computed SignalK metrics such as runtime, current level, etc."
integer id "{NOT_NULL}"
double_precision max_speed "max speed in knots"
double_precision max_wind_speed "true wind speed converted in knots, m/s from signalk plugin"
text name
text notes
tgeogpoint trip "MobilityDB trajectory, speed in m/s, distance in meters"
tfloat trip_awa "AWA (Apparent Wind Angle) in degrees converted from radians by signalk plugin"
tfloat trip_aws "AWS (Apparent Wind Speed), windSpeedApparent in knots converted by signalk plugin"
tfloat trip_batt_charge "Battery Charge"
tfloat trip_batt_voltage "Battery Voltage"
tfloat trip_cog "COG - Course Over Ground True in degrees converted from radians by signalk plugin"
tfloat trip_depth "Depth in meters, raw from signalk plugin"
tfloat trip_heading "Heading True in degrees converted from radians, raw from signalk plugin"
tfloat trip_hum_out "Humidity outside"
ttext trip_notes
tfloat trip_pres_out "Pressure outside"
tfloat trip_sog "SOG - Speed Over Ground in knots converted by signalk plugin"
tfloat trip_solar_power "solar powerPanel"
tfloat trip_solar_voltage "solar voltage"
ttext trip_status
tfloat trip_tank_level "Tank currentLevel"
tfloat trip_temp_out "Temperature outside in Kelvin, raw from signalk plugin"
tfloat trip_temp_water "Temperature water in Kelvin, raw from signalk plugin"
tfloat trip_twd "TWD - True Wind Direction in degrees converted from radians, raw from signalk plugin"
tfloat trip_tws "TWS - True Wind Speed in knots converted from m/s, raw from signalk plugin"
jsonb user_data "User-defined data Log-specific data including actual tags, observations, images and custom fields"
text vessel_id "Unique identifier for the vessel associated with the api.metadata entry {NOT_NULL}"
}
api_metadata {
boolean active "trigger monitor online/offline"
boolean active
jsonb available_keys "Signalk paths with unit for custom mapping"
jsonb available_keys
double_precision beam
jsonb configuration "User-defined Signalk path mapping for metrics"
jsonb configuration
timestamp_with_time_zone created_at "{NOT_NULL}"
double_precision height
text ip "Store vessel ip address"
text ip
double_precision length
text mmsi "Maritime Mobile Service Identity (MMSI) number associated with the vessel, link to public.mid"
text mmsi
text name
text platform
text plugin_version "{NOT_NULL}"
numeric ship_type "Type of ship associated with the vessel, link to public.aistypes"
numeric ship_type
text signalk_version "{NOT_NULL}"
timestamp_with_time_zone time "{NOT_NULL}"
timestamp_with_time_zone updated_at "{NOT_NULL}"
jsonb user_data "User-defined data including vessel polar (theoretical performance), make/model, and preferences"
jsonb user_data
text vessel_id "Link auth.vessels with api.metadata via FOREIGN KEY and REFERENCES {NOT_NULL}"
text vessel_id "{NOT_NULL}"
}
api_metrics {
double_precision anglespeedapparent
text client_id "Deprecated client_id to be removed"
double_precision courseovergroundtrue
double_precision latitude "With CONSTRAINT but allow NULL value to be ignored silently by trigger"
double_precision longitude "With CONSTRAINT but allow NULL value to be ignored silently by trigger"
jsonb metrics
double_precision speedoverground
text status
timestamp_with_time_zone time "{NOT_NULL}"
text vessel_id "Unique identifier for the vessel associated with the api.metadata entry {NOT_NULL}"
double_precision windspeedapparent
}
api_moorages {
text country
geography geog "postgis geography type default SRID 4326 Unit: degres"
boolean home_flag
integer id "{NOT_NULL}"
double_precision latitude
double_precision longitude
text name
jsonb nominatim "Output of the nominatim reverse geocoding service, see https://nominatim.org/release-docs/develop/api/Reverse/"
text notes
jsonb overpass "Output of the overpass API, see https://wiki.openstreetmap.org/wiki/Overpass_API"
integer stay_code "Link api.stays_at with api.moorages via FOREIGN KEY and REFERENCES"
jsonb user_data "User-defined data Mooring-specific data including images and custom fields"
text vessel_id "Unique identifier for the vessel associated with the api.metadata entry {NOT_NULL}"
}
api_stays {
boolean active
timestamp_with_time_zone arrived "{NOT_NULL}"
timestamp_with_time_zone departed
interval duration "Best to use standard ISO 8601"
geography geog "postgis geography type default SRID 4326 Unit: degres"
integer id "{NOT_NULL}"
double_precision latitude
double_precision longitude
integer moorage_id "Link api.moorages with api.stays via FOREIGN KEY and REFERENCES"
text name
text notes
integer stay_code "Link api.stays_at with api.stays via FOREIGN KEY and REFERENCES"
jsonb user_data "User-defined data Stay-specific data including images and custom fields"
text vessel_id "Unique identifier for the vessel associated with the api.metadata entry {NOT_NULL}"
}
api_stays_at {
text description "{NOT_NULL}"
integer stay_code "{NOT_NULL}"
}
auth_accounts {
timestamp_with_time_zone connected_at "{NOT_NULL}"
timestamp_with_time_zone created_at "{NOT_NULL}"
citext email "{NOT_NULL}"
text first "User first name with CONSTRAINT CHECK {NOT_NULL}"
integer id "{NOT_NULL}"
text last "User last name with CONSTRAINT CHECK {NOT_NULL}"
text pass "{NOT_NULL}"
jsonb preferences
name role "{NOT_NULL}"
timestamp_with_time_zone updated_at "{NOT_NULL}"
text user_id "{NOT_NULL}"
}
auth_otp {
text otp_pass "{NOT_NULL}"
timestamp_with_time_zone otp_timestamp
smallint otp_tries "{NOT_NULL}"
citext user_email "{NOT_NULL}"
}
auth_vessels {
timestamp_with_time_zone created_at "{NOT_NULL}"
numeric mmsi "MMSI can be optional but if present must be a valid one and unique but must be in numeric range between 100000000 and 800000000"
text name "{NOT_NULL}"
citext owner_email "{NOT_NULL}"
name role "{NOT_NULL}"
timestamp_with_time_zone updated_at "{NOT_NULL}"
text vessel_id "{NOT_NULL}"
}
public_aistypes {
text description
numeric id
}
public_app_settings {
text name "application settings name key {NOT_NULL}"
text value "application settings value {NOT_NULL}"
}
public_badges {
text description
text name
}
public_email_templates {
text email_content
text email_subject
text name
text pushover_message
text pushover_title
}
public_geocoders {
text name
text reverse_url
text url
}
public_iso3166 {
text alpha_2
text alpha_3
text country
integer id
}
public_mid {
text country
integer country_id
numeric id
}
public_mobilitydb_opcache {
integer ltypnum
oid opid
integer opnum
integer rtypnum
}
public_ne_10m_geography_marine_polys {
text changed
text featurecla
geometry geom
integer gid "{NOT_NULL}"
text label
double_precision max_label
double_precision min_label
text name
text name_ar
text name_bn
text name_de
text name_el
text name_en
text name_es
text name_fa
text name_fr
text name_he
text name_hi
text name_hu
text name_id
text name_it
text name_ja
text name_ko
text name_nl
text name_pl
text name_pt
text name_ru
text name_sv
text name_tr
text name_uk
text name_ur
text name_vi
text name_zh
text name_zht
text namealt
bigint ne_id
text note
smallint scalerank
text wikidataid
}
public_process_queue {
text channel "{NOT_NULL}"
integer id "{NOT_NULL}"
text payload "{NOT_NULL}"
timestamp_with_time_zone processed
text ref_id "either user_id or vessel_id {NOT_NULL}"
timestamp_with_time_zone stored "{NOT_NULL}"
}
public_spatial_ref_sys {
character_varying auth_name
integer auth_srid
character_varying proj4text
integer srid "{NOT_NULL}"
character_varying srtext
}
api_logbook }o--|| api_metadata : ""
api_logbook }o--|| api_moorages : ""
api_logbook }o--|| api_moorages : ""
api_metrics }o--|| api_metadata : ""
api_moorages }o--|| api_metadata : ""
api_stays }o--|| api_metadata : ""
api_moorages }o--|| api_stays_at : ""
api_stays }o--|| api_moorages : ""
api_stays }o--|| api_stays_at : ""
auth_otp |o--|| auth_accounts : ""
auth_vessels }o--|| auth_accounts : ""
PostgSail
Description
PostgSail database documentation
Tables
| Name | Columns | Comment | Type |
|---|---|---|---|
| api.eventlogs_view | 6 | Event logs view | VIEW |
| api.explore_view | 3 | explore_view web view | VIEW |
| api.log_view | 21 | Log web view | VIEW |
| api.log_view3 | 21 | Log web materialized view with RLS applied | VIEW |
| api.logbook | 42 | Stores generated logbook | BASE TABLE |
| api.logs_geojson_view | 4 | List logs as geojson | VIEW |
| api.logs_view | 11 | Logs web view | VIEW |
| api.metadata | 18 | Stores metadata received from vessel, aka signalk plugin | BASE TABLE |
| api.metrics | 11 | Stores metrics from vessel | BASE TABLE |
| api.monitoring_humidity | 3 | Monitoring environment.%.humidity web view | VIEW |
| api.monitoring_live | 23 | Dynamic Monitoring web view | VIEW |
| api.monitoring_temperatures | 3 | Monitoring environment.%.temperature web view | VIEW |
| api.monitoring_view | 18 | Monitoring static web view | VIEW |
| api.monitoring_view2 | 2 | Monitoring Last whatever data from json web view | VIEW |
| api.monitoring_view3 | 3 | Monitoring Timeseries whatever data from json web view | VIEW |
| api.monitoring_voltage | 3 | Monitoring electrical.%.voltage web view | VIEW |
| api.moorage_view | 18 | Moorage details web view | VIEW |
| api.moorages | 13 | Stores generated moorages | BASE TABLE |
| api.moorages_geojson_view | 3 | List moorages as geojson | VIEW |
| api.moorages_stays_view | 10 | Moorages stay listing web view | VIEW |
| api.moorages_view | 6 | Moorages listing web view | VIEW |
| api.stats_logs_view | 9 | Statistics Logs web view | VIEW |
| api.stats_moorages_away_view | 2 | Statistics Moorages Time Spent Away web view | VIEW |
| api.stats_moorages_view | 4 | Statistics Moorages web view | VIEW |
| api.stay_explore_view | 14 | List moorages notes order by stays | VIEW |
| api.stay_view | 18 | Stay web view | VIEW |
| api.stays | 14 | Stores generated stays | BASE TABLE |
| api.stays_at | 2 | Stay Type | BASE TABLE |
| api.stays_geojson_view | 1 | List stays as geojson | VIEW |
| api.stays_view | 16 | Stays web view | VIEW |
| api.total_info_view | 3 | total_info_view web view | VIEW |
| api.versions_view | 5 | Expose as a table view app and system version to API | VIEW |
| api.vessels_view | 9 | Expose vessels listing to web api | VIEW |
| auth.accounts | 11 | users account table | BASE TABLE |
| auth.otp | 4 | Stores temporal otp code for up to 15 minutes | BASE TABLE |
| auth.vessels | 7 | vessels table link to accounts email user_id column | BASE TABLE |
| public.aistypes | 2 | aistypes AIS Ship Types, https://api.vesselfinder.com/docs/ref-aistypes.html | BASE TABLE |
| public.app_settings | 2 | application settings | BASE TABLE |
| public.badges | 2 | Badges descriptions | BASE TABLE |
| public.email_templates | 5 | email/message templates for notifications | BASE TABLE |
| public.geocoders | 3 | geo service nominatim url | BASE TABLE |
| public.iso3166 | 4 | This is a complete list of all country ISO codes as described in the ISO 3166 international standard. Country Codes Alpha-2 & Alpha-3 https://www.iban.com/country-codes | BASE TABLE |
| public.mid | 3 | MMSI MID Codes (Maritime Mobile Service Identity) Filtered by Flag of Registration, https://www.marinevesseltraffic.com/2013/11/mmsi-mid-codes-by-flag.html | BASE TABLE |
| public.process_queue | 6 | process queue for async job | BASE TABLE |
Stored procedures and functions
| Name | ReturnType | Arguments | Type |
|---|---|---|---|
| api.counts_fn | jsonb | FUNCTION | |
| api.delete_logbook_fn | bool | _id integer | FUNCTION |
| api.delete_trip_entry_fn | void | _id integer, update_string tstzspan | FUNCTION |
| api.email_fn | bool | token text | FUNCTION |
| api.export_logbook_geojson_linestring_trip_fn | jsonb | _id integer | FUNCTION |
| api.export_logbook_geojson_point_trip_fn | jsonb | _id integer | FUNCTION |
| api.export_logbook_geojson_trip_fn | jsonb | _id integer | FUNCTION |
| api.export_logbook_gpx_trip_fn | text/xml | _id integer | FUNCTION |
| api.export_logbook_kml_trip_fn | text/xml | _id integer | FUNCTION |
| api.export_logbook_metrics_trip_fn | jsonb | _id integer | FUNCTION |
| api.export_logbook_polar_csv_fn | text | _id integer | FUNCTION |
| api.export_logbooks_geojson_linestring_trips_fn | jsonb | start_log integer DEFAULT NULL::integer, end_log integer DEFAULT NULL::integer, start_date text DEFAULT NULL::text, end_date text DEFAULT NULL::text, OUT geojson jsonb | FUNCTION |
| api.export_logbooks_geojson_point_trips_fn | jsonb | start_log integer DEFAULT NULL::integer, end_log integer DEFAULT NULL::integer, start_date text DEFAULT NULL::text, end_date text DEFAULT NULL::text, OUT geojson jsonb | FUNCTION |
| api.export_logbooks_gpx_trips_fn | text/xml | start_log integer DEFAULT NULL::integer, end_log integer DEFAULT NULL::integer | FUNCTION |
| api.export_logbooks_kml_trips_fn | text/xml | start_log integer DEFAULT NULL::integer, end_log integer DEFAULT NULL::integer | FUNCTION |
| api.export_moorages_geojson_fn | jsonb | OUT geojson jsonb | FUNCTION |
| api.export_moorages_gpx_fn | text/xml | FUNCTION | |
| api.export_moorages_kml_fn | text/xml | FUNCTION | |
| api.export_stays_geojson_fn | jsonb | OUT geojson jsonb | FUNCTION |
| api.export_vessel_geojson_fn | jsonb | OUT geojson jsonb | FUNCTION |
| api.find_log_from_moorage_fn | jsonb | _id integer, OUT geojson jsonb | FUNCTION |
| api.find_log_to_moorage_fn | jsonb | _id integer, OUT geojson jsonb | FUNCTION |
| api.find_stay_from_moorage_fn | void | _id integer | FUNCTION |
| api.generate_otp_fn | text | email text | FUNCTION |
| api.ispublic_fn | bool | boat text, _type text, _id integer DEFAULT NULL::integer | FUNCTION |
| api.logbook_update_geojson_trip_fn | jsonb | _id integer | FUNCTION |
| api.login | jwt_token | email text, pass text | FUNCTION |
| api.logs_by_day_fn | jsonb | OUT charts jsonb | FUNCTION |
| api.logs_by_month_fn | jsonb | OUT charts jsonb | FUNCTION |
| api.merge_logbook_fn | void | id_start integer, id_end integer | FUNCTION |
| api.monitoring_history_fn | jsonb | time_interval text DEFAULT ‘24’::text, OUT history_metrics jsonb | FUNCTION |
| api.pushover_fn | bool | token text, pushover_user_key text | FUNCTION |
| api.pushover_subscribe_link_fn | json | OUT pushover_link json | FUNCTION |
| api.recover | bool | email text | FUNCTION |
| api.register_vessel | jwt_token | vessel_email text, vessel_mmsi text, vessel_name text | FUNCTION |
| api.reset | bool | pass text, token text, uuid text | FUNCTION |
| api.settings_fn | json | OUT settings json | FUNCTION |
| api.signup | jwt_token | email text, pass text, firstname text, lastname text | FUNCTION |
| api.stats_fn | jsonb | start_date text DEFAULT NULL::text, end_date text DEFAULT NULL::text, OUT stats jsonb | FUNCTION |
| api.stats_logs_fn | jsonb | start_date text DEFAULT NULL::text, end_date text DEFAULT NULL::text, OUT stats jsonb | FUNCTION |
| api.stats_stays_fn | json | start_date text DEFAULT NULL::text, end_date text DEFAULT NULL::text, OUT stats json | FUNCTION |
| api.status_fn | jsonb | OUT status jsonb | FUNCTION |
| api.telegram | jwt_token | user_id bigint, email text DEFAULT NULL::text | FUNCTION |
| api.telegram_fn | bool | token text, telegram_obj text | FUNCTION |
| api.telegram_otp_fn | text | email text, OUT otp_code text | FUNCTION |
| api.update_logbook_observations_fn | bool | _id integer, observations text | FUNCTION |
| api.update_metadata_userdata_fn | bool | userdata text | FUNCTION |
| api.update_trip_notes_fn | void | _id integer, update_string ttext | FUNCTION |
| api.update_user_preferences_fn | bool | key text, value text | FUNCTION |
| api.versions_fn | json | FUNCTION | |
| api.vessel_details_fn | jsonb | FUNCTION | |
| api.vessel_extended_fn | jsonb | FUNCTION | |
| api.vessel_fn | jsonb | OUT vessel jsonb | FUNCTION |
| auth.check_role_exists | trigger | FUNCTION | |
| auth.encrypt_pass | trigger | FUNCTION | |
| auth.telegram_session_exists_fn | bool | user_id bigint | FUNCTION |
| auth.telegram_user_exists_fn | bool | email text, user_id bigint | FUNCTION |
| auth.user_role | name | email text, pass text | FUNCTION |
| auth.verify_otp_fn | text | token text | FUNCTION |
| public.autodiscovery_config_fn | jsonb | input_json jsonb | FUNCTION |
| public.badges_geom_fn | void | logbook_id integer, logbook_time text | FUNCTION |
| public.badges_logbook_fn | void | logbook_id integer, logbook_time text | FUNCTION |
| public.badges_moorages_fn | void | FUNCTION | |
| public.cron_alerts_fn | void | FUNCTION | |
| public.cron_process_autodiscovery_fn | void | FUNCTION | |
| public.cron_process_grafana_fn | void | FUNCTION | |
| public.cron_process_monitor_offline_fn | void | FUNCTION | |
| public.cron_process_monitor_online_fn | void | FUNCTION | |
| public.cron_process_new_logbook_fn | void | FUNCTION | |
| public.cron_process_new_notification_fn | void | FUNCTION | |
| public.cron_process_new_stay_fn | void | FUNCTION | |
| public.cron_process_post_logbook_fn | void | FUNCTION | |
| public.cron_process_pre_logbook_fn | void | FUNCTION | |
| public.cron_prune_otp_fn | void | FUNCTION | |
| public.cron_windy_fn | void | FUNCTION | |
| public.debug_trigger_fn | trigger | FUNCTION | |
| public.delete_vessel_fn | jsonb | _vessel_id text | FUNCTION |
| public.dump_account_fn | bool | _email text, _vessel_id text | FUNCTION |
| public.export_logbook_polar_fn | record | _id integer | FUNCTION |
| public.generate_uid_fn | text | size integer | FUNCTION |
| public.geojson_py_fn | jsonb | original jsonb, geometry_type text | FUNCTION |
| public.get_app_settings_fn | jsonb | OUT app_settings jsonb | FUNCTION |
| public.get_app_url_fn | jsonb | OUT app_settings jsonb | FUNCTION |
| public.get_user_settings_from_vesselid_fn | jsonb | vesselid text, OUT user_settings jsonb | FUNCTION |
| public.grafana_py_fn | void | _v_name text, _v_id text, _u_email text, app jsonb | FUNCTION |
| public.has_vessel_fn | bool | FUNCTION | |
| public.has_vessel_metadata_fn | bool | FUNCTION | |
| public.logbook_active_geojson_fn | jsonb | OUT _track_geojson jsonb | FUNCTION |
| public.logbook_completed_trigger_fn | trigger | FUNCTION | |
| public.logbook_delete_trigger_fn | trigger | FUNCTION | |
| public.logbook_get_extra_json_fn | json | search text, OUT output_json json | FUNCTION |
| public.logbook_metrics_dwithin_fn | numeric | _start text, _end text, lgn double precision, lat double precision, OUT count_metric numeric | FUNCTION |
| public.logbook_metrics_timebucket_fn | bool | bucket_interval text, _id integer, _start timestamp with time zone, _end timestamp with time zone, OUT timebucket boolean | FUNCTION |
| public.logbook_timelapse_geojson_fn | void | _id integer | FUNCTION |
| public.logbook_update_avg_fn | record | _id integer, _start text, _end text, OUT avg_speed double precision, OUT max_speed double precision, OUT max_wind_speed double precision, OUT avg_wind_speed double precision, OUT count_metric integer | FUNCTION |
| public.logbook_update_extra_json_fn | json | _id integer, _start text, _end text, OUT _extra_json json | FUNCTION |
| public.logbook_update_geojson_fn | json | _id integer, _start text, _end text, OUT _track_geojson json | FUNCTION |
| public.logbook_update_geom_distance_fn | record | _id integer, _start text, _end text, OUT _track_geom geometry, OUT _track_distance double precision | FUNCTION |
| public.logbook_update_gpx_fn | xml | _id integer, _start text, _end text, OUT _track_gpx xml | FUNCTION |
| public.logbook_update_metrics_short_fn | record | total_entry integer, start_date timestamp with time zone, end_date timestamp with time zone | FUNCTION |
| public.logbook_update_metrics_timebucket_fn | record | total_entry integer, start_date timestamp with time zone, end_date timestamp with time zone | FUNCTION |
| public.metadata_autodiscovery_trigger_fn | trigger | FUNCTION | |
| public.metadata_grafana_trigger_fn | trigger | FUNCTION | |
| public.metadata_upsert_trigger_fn | trigger | FUNCTION | |
| public.metrics_trigger_fn | trigger | FUNCTION | |
| public.moorage_delete_trigger_fn | trigger | FUNCTION | |
| public.moorage_update_trigger_fn | trigger | FUNCTION | |
| public.new_account_entry_fn | trigger | FUNCTION | |
| public.new_account_otp_validation_entry_fn | trigger | FUNCTION | |
| public.new_vessel_entry_fn | trigger | FUNCTION | |
| public.new_vessel_public_fn | trigger | FUNCTION | |
| public.new_vessel_trim_fn | trigger | FUNCTION | |
| public.overpass_py_fn | jsonb | lon numeric, lat numeric, retry boolean DEFAULT false, OUT geo jsonb | FUNCTION |
| public.process_account_otp_validation_queue_fn | void | _email text | FUNCTION |
| public.process_account_queue_fn | void | _email text | FUNCTION |
| public.process_lat_lon_fn | record | lon numeric, lat numeric, OUT moorage_id integer, OUT moorage_type integer, OUT moorage_name text, OUT moorage_country text | FUNCTION |
| public.process_logbook_queue_fn | void | _id integer | FUNCTION |
| public.process_moorage_queue_fn | void | _id integer | FUNCTION |
| public.process_notification_queue_fn | void | _email text, message_type text | FUNCTION |
| public.process_post_logbook_fn | void | _id integer | FUNCTION |
| public.process_pre_logbook_fn | void | _id integer | FUNCTION |
| public.process_stay_queue_fn | void | _id integer | FUNCTION |
| public.process_vessel_queue_fn | void | _email text | FUNCTION |
| public.reverse_geocode_py_fn | jsonb | geocoder text, lon numeric, lat numeric, OUT geo jsonb | FUNCTION |
| public.reverse_geoip_py_fn | jsonb | _ip text | FUNCTION |
| public.send_email_py_fn | void | email_type text, _user jsonb, app jsonb | FUNCTION |
| public.send_notification_fn | void | email_type text, user_settings jsonb | FUNCTION |
| public.send_pushover_py_fn | void | message_type text, _user jsonb, app jsonb | FUNCTION |
| public.send_telegram_py_fn | void | message_type text, _user jsonb, app jsonb | FUNCTION |
| public.set_vessel_settings_from_vesselid_fn | jsonb | vesselid text, OUT vessel_settings jsonb | FUNCTION |
| public.split_logbook_by24h_fn | record | _id integer | FUNCTION |
| public.split_logbook_by24h_geojson_fn | jsonb | _id integer | FUNCTION |
| public.stay_active_geojson_fn | jsonb | _time timestamp with time zone DEFAULT now(), OUT _track_geojson jsonb | FUNCTION |
| public.stay_completed_trigger_fn | trigger | FUNCTION | |
| public.stay_delete_trigger_fn | trigger | FUNCTION | |
| public.stay_in_progress_fn | int4 | _vessel_id text | FUNCTION |
| public.trip_in_progress_fn | int4 | _vessel_id text | FUNCTION |
| public.update_logbook_with_geojson_trigger_fn | trigger | FUNCTION | |
| public.update_metadata_configuration_trigger_fn | trigger | FUNCTION | |
| public.update_metadata_userdata_added_at_trigger_fn | trigger | FUNCTION | |
| public.update_tbl_userdata_added_at_trigger_fn | trigger | FUNCTION | |
| public.urlencode_py_fn | text | uri text | FUNCTION |
| public.urlescape_py_fn | text | original text | FUNCTION |
| public.windy_pws_py_fn | jsonb | metric jsonb, _user jsonb, app jsonb | FUNCTION |
Enums
| Name | Values |
|---|---|
| public.public_type | public_logs, public_logs_list, public_monitoring, public_stats, public_timelapse |
| public.status_type | anchored, moored, motoring, sailing |
Relations
erDiagram
"api.logbook" }o--|| "api.metadata" : "FOREIGN KEY (vessel_id) REFERENCES api.metadata(vessel_id) ON DELETE RESTRICT"
"api.logbook" }o--o| "api.moorages" : "FOREIGN KEY (_from_moorage_id) REFERENCES api.moorages(id) ON DELETE RESTRICT"
"api.logbook" }o--o| "api.moorages" : "FOREIGN KEY (_to_moorage_id) REFERENCES api.moorages(id) ON DELETE RESTRICT"
"api.metadata" |o--|| "auth.vessels" : "FOREIGN KEY (vessel_id) REFERENCES auth.vessels(vessel_id) ON DELETE RESTRICT"
"api.metrics" }o--|| "api.metadata" : "FOREIGN KEY (vessel_id) REFERENCES api.metadata(vessel_id) ON DELETE RESTRICT"
"api.moorages" }o--|| "api.metadata" : "FOREIGN KEY (vessel_id) REFERENCES api.metadata(vessel_id) ON DELETE RESTRICT"
"api.moorages" }o--o| "api.stays_at" : "FOREIGN KEY (stay_code) REFERENCES api.stays_at(stay_code) ON DELETE RESTRICT"
"api.stays" }o--|| "api.metadata" : "FOREIGN KEY (vessel_id) REFERENCES api.metadata(vessel_id) ON DELETE RESTRICT"
"api.stays" }o--o| "api.moorages" : "FOREIGN KEY (moorage_id) REFERENCES api.moorages(id) ON DELETE RESTRICT"
"api.stays" }o--o| "api.stays_at" : "FOREIGN KEY (stay_code) REFERENCES api.stays_at(stay_code) ON DELETE RESTRICT"
"auth.otp" |o--|| "auth.accounts" : "FOREIGN KEY (user_email) REFERENCES auth.accounts(email) ON DELETE RESTRICT"
"auth.vessels" }o--|| "auth.accounts" : "FOREIGN KEY (owner_email) REFERENCES auth.accounts(email) ON DELETE RESTRICT"
"api.eventlogs_view" {
text channel ""
integer id ""
text payload ""
timestamp_with_time_zone processed ""
text ref_id ""
timestamp_with_time_zone stored ""
}
"api.explore_view" {
text key ""
timestamp_with_time_zone time ""
text value ""
}
"api.log_view" {
double_precision avg_speed ""
numeric distance ""
interval duration ""
timestamp_with_time_zone ended ""
jsonb extra ""
text from ""
integer from_moorage_id ""
jsonb geojson ""
boolean has_images ""
integer id ""
jsonb images ""
double_precision max_speed ""
double_precision max_wind_speed ""
text name ""
text notes ""
jsonb observations ""
jsonb polar ""
timestamp_with_time_zone started ""
jsonb tags ""
text to ""
integer to_moorage_id ""
}
"api.log_view3" {
double_precision avg_speed ""
numeric distance ""
interval duration ""
timestamp_with_time_zone ended ""
jsonb extra ""
text from ""
integer from_moorage_id ""
jsonb geojson ""
boolean has_images ""
integer id ""
jsonb images ""
double_precision max_speed ""
double_precision max_wind_speed ""
text name ""
text notes ""
jsonb observations ""
jsonb polar ""
timestamp_with_time_zone started ""
jsonb tags ""
text to ""
integer to_moorage_id ""
}
"api.logbook" {
text _from "Name of the location where the log started, usually a moorage name"
double_precision _from_lat ""
double_precision _from_lng ""
integer _from_moorage_id FK "Link api.moorages with api.logbook via FOREIGN KEY and REFERENCES"
timestamp_with_time_zone _from_time ""
text _to "Name of the location where the log ended, usually a moorage name"
double_precision _to_lat ""
double_precision _to_lng ""
integer _to_moorage_id FK "Link api.moorages with api.logbook via FOREIGN KEY and REFERENCES"
timestamp_with_time_zone _to_time ""
boolean active ""
double_precision avg_speed "avg speed in knots"
numeric distance "Distance in Nautical Miles converted mobilitydb meters to NM"
interval duration "Duration in ISO 8601 format"
jsonb extra "Computed SignalK metrics such as runtime, current level, etc."
integer id ""
double_precision max_speed "max speed in knots"
double_precision max_wind_speed "true wind speed converted in knots, m/s from signalk plugin"
text name ""
text notes ""
tgeogpoint trip "MobilityDB trajectory, speed in m/s, distance in meters"
tfloat trip_awa "AWA (Apparent Wind Angle) in degrees converted from radians by signalk plugin"
tfloat trip_aws "AWS (Apparent Wind Speed), windSpeedApparent in knots converted by signalk plugin"
tfloat trip_batt_charge "Battery Charge"
tfloat trip_batt_voltage "Battery Voltage"
tfloat trip_cog "COG - Course Over Ground True in degrees converted from radians by signalk plugin"
tfloat trip_depth "Depth in meters, raw from signalk plugin"
tfloat trip_heading "Heading True in degrees converted from radians, raw from signalk plugin"
tfloat trip_hum_out "Humidity outside"
ttext trip_notes ""
tfloat trip_pres_out "Pressure outside"
tfloat trip_sog "SOG - Speed Over Ground in knots converted by signalk plugin"
tfloat trip_solar_power "solar powerPanel"
tfloat trip_solar_voltage "solar voltage"
ttext trip_status ""
tfloat trip_tank_level "Tank currentLevel"
tfloat trip_temp_out "Temperature outside in Kelvin, raw from signalk plugin"
tfloat trip_temp_water "Temperature water in Kelvin, raw from signalk plugin"
tfloat trip_twd "TWD - True Wind Direction in degrees converted from radians, raw from signalk plugin"
tfloat trip_tws "TWS - True Wind Speed in knots converted from m/s, raw from signalk plugin"
jsonb user_data "User-defined data Log-specific data including actual tags, observations, images and custom fields"
text vessel_id FK "Unique identifier for the vessel associated with the api.metadata entry"
}
"api.logs_geojson_view" {
jsonb geojson ""
integer id ""
text name ""
timestamp_with_time_zone starttimestamp ""
}
"api.logs_view" {
integer _from_moorage_id ""
integer _to_moorage_id ""
numeric distance ""
interval duration ""
timestamp_with_time_zone ended ""
text from ""
integer id ""
text name ""
timestamp_with_time_zone started ""
jsonb tags ""
text to ""
}
"api.metadata" {
boolean active "trigger monitor online/offline"
jsonb available_keys "Signalk paths with unit for custom mapping"
double_precision beam ""
jsonb configuration "User-defined Signalk path mapping for metrics"
timestamp_with_time_zone created_at ""
double_precision height ""
text ip "Store vessel ip address"
double_precision length ""
text mmsi "Maritime Mobile Service Identity (MMSI) number associated with the vessel, link to public.mid"
text name ""
text platform ""
text plugin_version ""
numeric ship_type "Type of ship associated with the vessel, link to public.aistypes"
text signalk_version ""
timestamp_with_time_zone time ""
timestamp_with_time_zone updated_at ""
jsonb user_data "User-defined data including vessel polar (theoretical performance), make/model, and preferences"
text vessel_id FK "Link auth.vessels with api.metadata via FOREIGN KEY and REFERENCES"
}
"api.metrics" {
double_precision anglespeedapparent ""
text client_id "Deprecated client_id to be removed"
double_precision courseovergroundtrue ""
double_precision latitude "With CONSTRAINT but allow NULL value to be ignored silently by trigger"
double_precision longitude "With CONSTRAINT but allow NULL value to be ignored silently by trigger"
jsonb metrics ""
double_precision speedoverground ""
text status ""
timestamp_with_time_zone time ""
text vessel_id FK "Unique identifier for the vessel associated with the api.metadata entry"
double_precision windspeedapparent ""
}
"api.monitoring_humidity" {
text key ""
timestamp_with_time_zone time ""
text value ""
}
"api.monitoring_live" {
double_precision batterycharge ""
double_precision batteryvoltage ""
jsonb data ""
double_precision depth ""
jsonb geojson ""
double_precision insidehumidity ""
double_precision insidepressure ""
double_precision insidetemperature ""
jsonb live ""
text name ""
boolean offline ""
double_precision outsidehumidity ""
double_precision outsidepressure ""
json outsidepressurehistory ""
double_precision outsidetemperature ""
double_precision solarpower ""
double_precision solarvoltage ""
text status ""
double_precision tanklevel ""
timestamp_with_time_zone time ""
double_precision watertemperature ""
double_precision winddirectiontrue ""
double_precision windspeedoverground ""
}
"api.monitoring_temperatures" {
text key ""
timestamp_with_time_zone time ""
text value ""
}
"api.monitoring_view" {
jsonb batterycharge ""
jsonb batteryvoltage ""
jsonb depth ""
jsonb geojson ""
jsonb insidehumidity ""
jsonb insidepressure ""
jsonb insidetemperature ""
jsonb live ""
text name ""
boolean offline ""
jsonb outsidehumidity ""
jsonb outsidepressure ""
jsonb outsidetemperature ""
text status ""
timestamp_with_time_zone time ""
jsonb watertemperature ""
jsonb winddirectiontrue ""
jsonb windspeedoverground ""
}
"api.monitoring_view2" {
text key ""
jsonb value ""
}
"api.monitoring_view3" {
text key ""
timestamp_with_time_zone time ""
text value ""
}
"api.monitoring_voltage" {
text key ""
timestamp_with_time_zone time ""
text value ""
}
"api.moorage_view" {
text default_stay ""
integer default_stay_id ""
geography_Point_4326_ geog ""
boolean has_images ""
boolean home ""
integer id ""
jsonb images ""
double_precision latitude ""
bigint logs_count ""
double_precision longitude ""
text name ""
text notes ""
timestamp_with_time_zone stay_first_seen ""
integer stay_first_seen_id ""
timestamp_with_time_zone stay_last_seen ""
integer stay_last_seen_id ""
bigint stays_count ""
interval stays_sum_duration ""
}
"api.moorages" {
text country ""
geography_Point_4326_ geog "postgis geography type default SRID 4326 Unit: degres"
boolean home_flag ""
integer id ""
double_precision latitude ""
double_precision longitude ""
text name ""
jsonb nominatim "Output of the nominatim reverse geocoding service, see https://nominatim.org/release-docs/develop/api/Reverse/"
text notes ""
jsonb overpass "Output of the overpass API, see https://wiki.openstreetmap.org/wiki/Overpass_API"
integer stay_code FK "Link api.stays_at with api.moorages via FOREIGN KEY and REFERENCES"
jsonb user_data "User-defined data Mooring-specific data including images and custom fields"
text vessel_id FK "Unique identifier for the vessel associated with the api.metadata entry"
}
"api.moorages_geojson_view" {
jsonb geojson ""
integer id ""
text name ""
}
"api.moorages_stays_view" {
integer _from_id ""
text _from_name ""
timestamp_with_time_zone _from_time ""
integer _to_id ""
text _to_name ""
timestamp_with_time_zone _to_time ""
interval duration ""
integer id ""
text name ""
integer stay_code ""
}
"api.moorages_view" {
bigint arrivals_departures ""
text default_stay ""
integer default_stay_id ""
integer id ""
text moorage ""
interval total_duration ""
}
"api.stats_logs_view" {
timestamp_with_time_zone first ""
timestamp_with_time_zone last ""
text longest_nonstop_sail ""
double_precision max_speed ""
double_precision max_wind_speed ""
text name ""
bigint number_of_log_entries ""
numeric total_distance ""
interval total_time_underway ""
}
"api.stats_moorages_away_view" {
text description ""
interval time_spent_away_by ""
}
"api.stats_moorages_view" {
bigint home_ports ""
interval time_spent_at_home_port(s) ""
interval time_spent_away ""
bigint unique_moorages ""
}
"api.stay_explore_view" {
timestamp_with_time_zone arrived ""
boolean has_images ""
integer id ""
jsonb images ""
double_precision latitude ""
double_precision longitude ""
integer moorage_id ""
text moorage_name ""
text moorage_notes ""
text name ""
integer stay_code ""
integer stay_id ""
text stay_name ""
text stay_notes ""
}
"api.stay_view" {
timestamp_with_time_zone arrived ""
integer arrived_from_moorage_id ""
text arrived_from_moorage_name ""
integer arrived_log_id ""
timestamp_with_time_zone departed ""
integer departed_log_id ""
integer departed_to_moorage_id ""
text departed_to_moorage_name ""
interval duration ""
boolean has_images ""
integer id ""
jsonb images ""
text moorage ""
integer moorage_id ""
text name ""
text notes ""
text stayed_at ""
integer stayed_at_id ""
}
"api.stays" {
boolean active ""
timestamp_with_time_zone arrived ""
timestamp_with_time_zone departed ""
interval duration "Best to use standard ISO 8601"
geography_Point_4326_ geog "postgis geography type default SRID 4326 Unit: degres"
integer id ""
double_precision latitude ""
double_precision longitude ""
integer moorage_id FK "Link api.moorages with api.stays via FOREIGN KEY and REFERENCES"
text name ""
text notes ""
integer stay_code FK "Link api.stays_at with api.stays via FOREIGN KEY and REFERENCES"
jsonb user_data "User-defined data Stay-specific data including images and custom fields"
text vessel_id FK "Unique identifier for the vessel associated with the api.metadata entry"
}
"api.stays_at" {
text description ""
integer stay_code ""
}
"api.stays_geojson_view" {
jsonb geojson ""
}
"api.stays_view" {
timestamp_with_time_zone arrived ""
integer arrived_from_moorage_id ""
text arrived_from_moorage_name ""
integer arrived_log_id ""
timestamp_with_time_zone departed ""
integer departed_log_id ""
integer departed_to_moorage_id ""
text departed_to_moorage_name ""
interval duration ""
integer id ""
text moorage ""
integer moorage_id ""
text name ""
text notes ""
text stayed_at ""
integer stayed_at_id ""
}
"api.total_info_view" {
bigint logs ""
bigint moorages ""
bigint stays ""
}
"api.versions_view" {
text api_version ""
text postgis ""
text postgrest ""
text sys_version ""
text timescaledb ""
}
"api.vessels_view" {
timestamp_with_time_zone created_at ""
interval duration ""
interval duration_last_metrics ""
text last_contact ""
text last_metrics ""
boolean metrics_offline ""
numeric mmsi ""
text name ""
boolean offline ""
}
"auth.accounts" {
timestamp_with_time_zone connected_at ""
timestamp_with_time_zone created_at ""
citext email ""
text first "User first name with CONSTRAINT CHECK"
integer id ""
text last "User last name with CONSTRAINT CHECK"
text pass ""
jsonb preferences ""
name role ""
timestamp_with_time_zone updated_at ""
text user_id ""
}
"auth.otp" {
text otp_pass ""
timestamp_with_time_zone otp_timestamp ""
smallint otp_tries ""
citext user_email FK ""
}
"auth.vessels" {
timestamp_with_time_zone created_at ""
numeric mmsi "MMSI can be optional but if present must be a valid one and unique but must be in numeric range between 100000000 and 800000000"
text name ""
citext owner_email FK ""
name role ""
timestamp_with_time_zone updated_at ""
text vessel_id ""
}
"public.aistypes" {
text description ""
numeric id ""
}
"public.app_settings" {
text name "application settings name key"
text value "application settings value"
}
"public.badges" {
text description ""
text name ""
}
"public.email_templates" {
text email_content ""
text email_subject ""
text name ""
text pushover_message ""
text pushover_title ""
}
"public.geocoders" {
text name ""
text reverse_url ""
text url ""
}
"public.iso3166" {
text alpha_2 ""
text alpha_3 ""
text country ""
integer id ""
}
"public.mid" {
text country ""
integer country_id ""
numeric id ""
}
"public.process_queue" {
text channel ""
integer id ""
text payload ""
timestamp_with_time_zone processed ""
text ref_id "either user_id or vessel_id"
timestamp_with_time_zone stored ""
}
Generated by tbls
api.eventlogs_view
Description
Event logs view
Table Definition
CREATE VIEW eventlogs_view AS (
SELECT id,
channel,
payload,
ref_id,
stored,
processed
FROM process_queue pq
WHERE ((processed IS NOT NULL) AND (channel <> 'new_stay'::text) AND (channel <> 'pre_logbook'::text) AND (channel <> 'post_logbook'::text) AND ((ref_id = current_setting('user.id'::text, false)) OR (ref_id = current_setting('vessel.id'::text, true))))
ORDER BY id DESC
)
Columns
| Name | Type | Default | Nullable |
|---|---|---|---|
| channel | text | true | |
| id | integer | true | |
| payload | text | true | |
| processed | timestamp with time zone | true | |
| ref_id | text | true | |
| stored | timestamp with time zone | true |
Referenced Tables
| Name | Columns | Comment | Type |
|---|---|---|---|
| public.process_queue | 6 | process queue for async job | BASE TABLE |
Relations
erDiagram
"api.eventlogs_view" {
text channel ""
integer id ""
text payload ""
timestamp_with_time_zone processed ""
text ref_id ""
timestamp_with_time_zone stored ""
}
Generated by tbls
api.explore_view
Description
explore_view web view
Table Definition
CREATE VIEW explore_view AS (
WITH raw_metrics AS (
SELECT m."time",
m.metrics
FROM api.metrics m
ORDER BY m."time" DESC
LIMIT 1
)
SELECT raw_metrics."time",
jsonb_each_text.key,
jsonb_each_text.value
FROM raw_metrics,
LATERAL jsonb_each_text(raw_metrics.metrics) jsonb_each_text(key, value)
ORDER BY jsonb_each_text.key
)
Columns
| Name | Type | Default | Nullable |
|---|---|---|---|
| key | text | true | |
| time | timestamp with time zone | true | |
| value | text | true |
Referenced Tables
| Name | Columns | Comment | Type |
|---|---|---|---|
| api.metrics | 11 | Stores metrics from vessel | BASE TABLE |
Relations
erDiagram
"api.explore_view" {
text key ""
timestamp_with_time_zone time ""
text value ""
}
Generated by tbls
api.log_view
Description
Log web view
Table Definition
CREATE VIEW log_view AS (
SELECT id,
name,
_from AS "from",
_from_time AS started,
_to AS "to",
_to_time AS ended,
distance,
duration,
notes,
api.export_logbook_geojson_trip_fn(id) AS geojson,
avg_speed,
max_speed,
max_wind_speed,
extra,
_from_moorage_id AS from_moorage_id,
_to_moorage_id AS to_moorage_id,
(extra -> 'polar'::text) AS polar,
(user_data -> 'images'::text) AS images,
(user_data -> 'tags'::text) AS tags,
(user_data -> 'observations'::text) AS observations,
CASE
WHEN (jsonb_array_length((user_data -> 'images'::text)) > 0) THEN true
ELSE false
END AS has_images
FROM api.logbook l
WHERE ((_to_time IS NOT NULL) AND (trip IS NOT NULL))
ORDER BY _from_time DESC
)
Columns
| Name | Type | Default | Nullable |
|---|---|---|---|
| avg_speed | double precision | true | |
| distance | numeric | true | |
| duration | interval | true | |
| ended | timestamp with time zone | true | |
| extra | jsonb | true | |
| from | text | true | |
| from_moorage_id | integer | true | |
| geojson | jsonb | true | |
| has_images | boolean | true | |
| id | integer | true | |
| images | jsonb | true | |
| max_speed | double precision | true | |
| max_wind_speed | double precision | true | |
| name | text | true | |
| notes | text | true | |
| observations | jsonb | true | |
| polar | jsonb | true | |
| started | timestamp with time zone | true | |
| tags | jsonb | true | |
| to | text | true | |
| to_moorage_id | integer | true |
Referenced Tables
| Name | Columns | Comment | Type |
|---|---|---|---|
| api.logbook | 42 | Stores generated logbook | BASE TABLE |
Relations
erDiagram
"api.log_view" {
double_precision avg_speed ""
numeric distance ""
interval duration ""
timestamp_with_time_zone ended ""
jsonb extra ""
text from ""
integer from_moorage_id ""
jsonb geojson ""
boolean has_images ""
integer id ""
jsonb images ""
double_precision max_speed ""
double_precision max_wind_speed ""
text name ""
text notes ""
jsonb observations ""
jsonb polar ""
timestamp_with_time_zone started ""
jsonb tags ""
text to ""
integer to_moorage_id ""
}
Generated by tbls
api.logbook
Description
Stores generated logbook
Columns
| Name | Type | Default | Nullable | Parents | Comment |
|---|---|---|---|---|---|
| _from | text | true | Name of the location where the log started, usually a moorage name | ||
| _from_lat | double precision | true | |||
| _from_lng | double precision | true | |||
| _from_moorage_id | integer | true | api.moorages | Link api.moorages with api.logbook via FOREIGN KEY and REFERENCES | |
| _from_time | timestamp with time zone | false | |||
| _to | text | true | Name of the location where the log ended, usually a moorage name | ||
| _to_lat | double precision | true | |||
| _to_lng | double precision | true | |||
| _to_moorage_id | integer | true | api.moorages | Link api.moorages with api.logbook via FOREIGN KEY and REFERENCES | |
| _to_time | timestamp with time zone | true | |||
| active | boolean | false | true | ||
| avg_speed | double precision | true | avg speed in knots | ||
| distance | numeric | true | Distance in Nautical Miles converted mobilitydb meters to NM | ||
| duration | interval | true | Duration in ISO 8601 format | ||
| extra | jsonb | true | Computed SignalK metrics such as runtime, current level, etc. | ||
| id | integer | false | |||
| max_speed | double precision | true | max speed in knots | ||
| max_wind_speed | double precision | true | true wind speed converted in knots, m/s from signalk plugin | ||
| name | text | true | |||
| notes | text | true | |||
| trip | tgeogpoint | true | MobilityDB trajectory, speed in m/s, distance in meters | ||
| trip_awa | tfloat | true | AWA (Apparent Wind Angle) in degrees converted from radians by signalk plugin | ||
| trip_aws | tfloat | true | AWS (Apparent Wind Speed), windSpeedApparent in knots converted by signalk plugin | ||
| trip_batt_charge | tfloat | true | Battery Charge | ||
| trip_batt_voltage | tfloat | true | Battery Voltage | ||
| trip_cog | tfloat | true | COG - Course Over Ground True in degrees converted from radians by signalk plugin | ||
| trip_depth | tfloat | true | Depth in meters, raw from signalk plugin | ||
| trip_heading | tfloat | true | Heading True in degrees converted from radians, raw from signalk plugin | ||
| trip_hum_out | tfloat | true | Humidity outside | ||
| trip_notes | ttext | true | |||
| trip_pres_out | tfloat | true | Pressure outside | ||
| trip_sog | tfloat | true | SOG - Speed Over Ground in knots converted by signalk plugin | ||
| trip_solar_power | tfloat | true | solar powerPanel | ||
| trip_solar_voltage | tfloat | true | solar voltage | ||
| trip_status | ttext | true | |||
| trip_tank_level | tfloat | true | Tank currentLevel | ||
| trip_temp_out | tfloat | true | Temperature outside in Kelvin, raw from signalk plugin | ||
| trip_temp_water | tfloat | true | Temperature water in Kelvin, raw from signalk plugin | ||
| trip_twd | tfloat | true | TWD - True Wind Direction in degrees converted from radians, raw from signalk plugin | ||
| trip_tws | tfloat | true | TWS - True Wind Speed in knots converted from m/s, raw from signalk plugin | ||
| user_data | jsonb | ‘{}’::jsonb | true | User-defined data Log-specific data including actual tags, observations, images and custom fields | |
| vessel_id | text | false | api.metadata | Unique identifier for the vessel associated with the api.metadata entry |
Constraints
| Name | Type | Definition | Comment |
|---|---|---|---|
| logbook__from_moorage_id_fkey | FOREIGN KEY | FOREIGN KEY (_from_moorage_id) REFERENCES api.moorages(id) ON DELETE RESTRICT | |
| logbook__from_time_not_null | n | NOT NULL _from_time | |
| logbook__to_moorage_id_fkey | FOREIGN KEY | FOREIGN KEY (_to_moorage_id) REFERENCES api.moorages(id) ON DELETE RESTRICT | |
| logbook_id_not_null | n | NOT NULL id | |
| logbook_pkey | PRIMARY KEY | PRIMARY KEY (id) | |
| logbook_vessel_id_fkey | FOREIGN KEY | FOREIGN KEY (vessel_id) REFERENCES api.metadata(vessel_id) ON DELETE RESTRICT | Link api.stays with api.metadata via vessel_id using FOREIGN KEY and REFERENCES |
| logbook_vessel_id_not_null | n | NOT NULL vessel_id |
Indexes
| Name | Definition |
|---|---|
| logbook_active_idx | CREATE INDEX logbook_active_idx ON api.logbook USING btree (active) |
| logbook_extra_idx | CREATE INDEX logbook_extra_idx ON api.logbook USING gin (extra) |
| logbook_from_moorage_id_idx | CREATE INDEX logbook_from_moorage_id_idx ON api.logbook USING btree (_from_moorage_id) |
| logbook_from_moorage_time_idx | CREATE INDEX logbook_from_moorage_time_idx ON api.logbook USING btree (_from_moorage_id, _from_time DESC) WHERE (_from_moorage_id IS NOT NULL) |
| logbook_from_time_idx | CREATE INDEX logbook_from_time_idx ON api.logbook USING btree (_from_time) |
| logbook_log_view_idx | CREATE INDEX logbook_log_view_idx ON api.logbook USING btree (_from_time DESC) WHERE ((_to_time IS NOT NULL) AND (trip IS NOT NULL)) |
| logbook_logs_view_idx | CREATE INDEX logbook_logs_view_idx ON api.logbook USING btree (_from_time DESC) WHERE ((_to_time IS NOT NULL) AND (name IS NOT NULL)) |
| logbook_pkey | CREATE UNIQUE INDEX logbook_pkey ON api.logbook USING btree (id) |
| logbook_to_moorage_id_idx | CREATE INDEX logbook_to_moorage_id_idx ON api.logbook USING btree (_to_moorage_id) |
| logbook_to_moorage_time_idx | CREATE INDEX logbook_to_moorage_time_idx ON api.logbook USING btree (_to_moorage_id, _to_time DESC) WHERE (_to_moorage_id IS NOT NULL) |
| logbook_to_time_idx | CREATE INDEX logbook_to_time_idx ON api.logbook USING btree (_to_time) |
| logbook_trip_idx | CREATE INDEX logbook_trip_idx ON api.logbook USING gist (trip) |
| logbook_user_data_idx | CREATE INDEX logbook_user_data_idx ON api.logbook USING gin (user_data) |
| logbook_vessel_active_idx | CREATE INDEX logbook_vessel_active_idx ON api.logbook USING btree (vessel_id, active, _from_time DESC) WHERE (active = true) |
| logbook_vessel_id_idx | CREATE INDEX logbook_vessel_id_idx ON api.logbook USING btree (vessel_id) |
| logbook_vessel_time_idx | CREATE INDEX logbook_vessel_time_idx ON api.logbook USING btree (vessel_id, _from_time DESC, _to_time DESC) INCLUDE (name, distance, duration) |
Triggers
| Name | Definition | Comment |
|---|---|---|
| logbook_delete_trigger | CREATE TRIGGER logbook_delete_trigger BEFORE DELETE ON api.logbook FOR EACH ROW EXECUTE FUNCTION logbook_delete_trigger_fn() | BEFORE DELETE ON api.logbook run function public.logbook_delete_trigger_fn to delete reference and logbook_ext need to deleted. |
| logbook_update_user_data_trigger | CREATE TRIGGER logbook_update_user_data_trigger BEFORE UPDATE ON api.logbook FOR EACH ROW EXECUTE FUNCTION update_tbl_userdata_added_at_trigger_fn() | BEFORE UPDATE ON api.logbook run function public.update_tbl_userdata_added_at_trigger_fn to update the user_data field with current date in ISO format when polar or images change |
Relations
erDiagram
"api.logbook" }o--o| "api.moorages" : "FOREIGN KEY (_from_moorage_id) REFERENCES api.moorages(id) ON DELETE RESTRICT"
"api.logbook" }o--o| "api.moorages" : "FOREIGN KEY (_to_moorage_id) REFERENCES api.moorages(id) ON DELETE RESTRICT"
"api.stays" }o--o| "api.moorages" : "FOREIGN KEY (moorage_id) REFERENCES api.moorages(id) ON DELETE RESTRICT"
"api.moorages" }o--o| "api.stays_at" : "FOREIGN KEY (stay_code) REFERENCES api.stays_at(stay_code) ON DELETE RESTRICT"
"api.moorages" }o--|| "api.metadata" : "FOREIGN KEY (vessel_id) REFERENCES api.metadata(vessel_id) ON DELETE RESTRICT"
"api.logbook" }o--|| "api.metadata" : "FOREIGN KEY (vessel_id) REFERENCES api.metadata(vessel_id) ON DELETE RESTRICT"
"api.metadata" |o--|| "auth.vessels" : "FOREIGN KEY (vessel_id) REFERENCES auth.vessels(vessel_id) ON DELETE RESTRICT"
"api.metrics" }o--|| "api.metadata" : "FOREIGN KEY (vessel_id) REFERENCES api.metadata(vessel_id) ON DELETE RESTRICT"
"api.stays" }o--|| "api.metadata" : "FOREIGN KEY (vessel_id) REFERENCES api.metadata(vessel_id) ON DELETE RESTRICT"
"api.logbook" {
text _from "Name of the location where the log started, usually a moorage name"
double_precision _from_lat ""
double_precision _from_lng ""
integer _from_moorage_id FK "Link api.moorages with api.logbook via FOREIGN KEY and REFERENCES"
timestamp_with_time_zone _from_time ""
text _to "Name of the location where the log ended, usually a moorage name"
double_precision _to_lat ""
double_precision _to_lng ""
integer _to_moorage_id FK "Link api.moorages with api.logbook via FOREIGN KEY and REFERENCES"
timestamp_with_time_zone _to_time ""
boolean active ""
double_precision avg_speed "avg speed in knots"
numeric distance "Distance in Nautical Miles converted mobilitydb meters to NM"
interval duration "Duration in ISO 8601 format"
jsonb extra "Computed SignalK metrics such as runtime, current level, etc."
integer id ""
double_precision max_speed "max speed in knots"
double_precision max_wind_speed "true wind speed converted in knots, m/s from signalk plugin"
text name ""
text notes ""
tgeogpoint trip "MobilityDB trajectory, speed in m/s, distance in meters"
tfloat trip_awa "AWA (Apparent Wind Angle) in degrees converted from radians by signalk plugin"
tfloat trip_aws "AWS (Apparent Wind Speed), windSpeedApparent in knots converted by signalk plugin"
tfloat trip_batt_charge "Battery Charge"
tfloat trip_batt_voltage "Battery Voltage"
tfloat trip_cog "COG - Course Over Ground True in degrees converted from radians by signalk plugin"
tfloat trip_depth "Depth in meters, raw from signalk plugin"
tfloat trip_heading "Heading True in degrees converted from radians, raw from signalk plugin"
tfloat trip_hum_out "Humidity outside"
ttext trip_notes ""
tfloat trip_pres_out "Pressure outside"
tfloat trip_sog "SOG - Speed Over Ground in knots converted by signalk plugin"
tfloat trip_solar_power "solar powerPanel"
tfloat trip_solar_voltage "solar voltage"
ttext trip_status ""
tfloat trip_tank_level "Tank currentLevel"
tfloat trip_temp_out "Temperature outside in Kelvin, raw from signalk plugin"
tfloat trip_temp_water "Temperature water in Kelvin, raw from signalk plugin"
tfloat trip_twd "TWD - True Wind Direction in degrees converted from radians, raw from signalk plugin"
tfloat trip_tws "TWS - True Wind Speed in knots converted from m/s, raw from signalk plugin"
jsonb user_data "User-defined data Log-specific data including actual tags, observations, images and custom fields"
text vessel_id FK "Unique identifier for the vessel associated with the api.metadata entry"
}
"api.moorages" {
text country ""
geography_Point_4326_ geog "postgis geography type default SRID 4326 Unit: degres"
boolean home_flag ""
integer id ""
double_precision latitude ""
double_precision longitude ""
text name ""
jsonb nominatim "Output of the nominatim reverse geocoding service, see https://nominatim.org/release-docs/develop/api/Reverse/"
text notes ""
jsonb overpass "Output of the overpass API, see https://wiki.openstreetmap.org/wiki/Overpass_API"
integer stay_code FK "Link api.stays_at with api.moorages via FOREIGN KEY and REFERENCES"
jsonb user_data "User-defined data Mooring-specific data including images and custom fields"
text vessel_id FK "Unique identifier for the vessel associated with the api.metadata entry"
}
"api.stays" {
boolean active ""
timestamp_with_time_zone arrived ""
timestamp_with_time_zone departed ""
interval duration "Best to use standard ISO 8601"
geography_Point_4326_ geog "postgis geography type default SRID 4326 Unit: degres"
integer id ""
double_precision latitude ""
double_precision longitude ""
integer moorage_id FK "Link api.moorages with api.stays via FOREIGN KEY and REFERENCES"
text name ""
text notes ""
integer stay_code FK "Link api.stays_at with api.stays via FOREIGN KEY and REFERENCES"
jsonb user_data "User-defined data Stay-specific data including images and custom fields"
text vessel_id FK "Unique identifier for the vessel associated with the api.metadata entry"
}
"api.stays_at" {
text description ""
integer stay_code ""
}
"api.metadata" {
boolean active "trigger monitor online/offline"
jsonb available_keys "Signalk paths with unit for custom mapping"
double_precision beam ""
jsonb configuration "User-defined Signalk path mapping for metrics"
timestamp_with_time_zone created_at ""
double_precision height ""
text ip "Store vessel ip address"
double_precision length ""
text mmsi "Maritime Mobile Service Identity (MMSI) number associated with the vessel, link to public.mid"
text name ""
text platform ""
text plugin_version ""
numeric ship_type "Type of ship associated with the vessel, link to public.aistypes"
text signalk_version ""
timestamp_with_time_zone time ""
timestamp_with_time_zone updated_at ""
jsonb user_data "User-defined data including vessel polar (theoretical performance), make/model, and preferences"
text vessel_id FK "Link auth.vessels with api.metadata via FOREIGN KEY and REFERENCES"
}
"auth.vessels" {
timestamp_with_time_zone created_at ""
numeric mmsi "MMSI can be optional but if present must be a valid one and unique but must be in numeric range between 100000000 and 800000000"
text name ""
citext owner_email FK ""
name role ""
timestamp_with_time_zone updated_at ""
text vessel_id ""
}
"api.metrics" {
double_precision anglespeedapparent ""
text client_id "Deprecated client_id to be removed"
double_precision courseovergroundtrue ""
double_precision latitude "With CONSTRAINT but allow NULL value to be ignored silently by trigger"
double_precision longitude "With CONSTRAINT but allow NULL value to be ignored silently by trigger"
jsonb metrics ""
double_precision speedoverground ""
text status ""
timestamp_with_time_zone time ""
text vessel_id FK "Unique identifier for the vessel associated with the api.metadata entry"
double_precision windspeedapparent ""
}
Generated by tbls
api.logs_geojson_view
Description
List logs as geojson
Table Definition
CREATE VIEW logs_geojson_view AS (
SELECT id,
name,
starttimestamp,
(st_asgeojson(tbl.*))::jsonb AS geojson
FROM ( SELECT l.id,
l.name,
starttimestamp(l.trip) AS starttimestamp,
endtimestamp(l.trip) AS endtimestamp,
duration(l.trip) AS duration,
((length(l.trip) * (0.0005399568)::double precision))::numeric AS distance,
maxvalue(l.trip_sog) AS max_sog,
maxvalue(l.trip_tws) AS max_tws,
maxvalue(l.trip_twd) AS max_twd,
maxvalue(l.trip_depth) AS max_depth,
maxvalue(l.trip_temp_water) AS max_temp_water,
maxvalue(l.trip_temp_out) AS max_temp_out,
maxvalue(l.trip_pres_out) AS max_pres_out,
maxvalue(l.trip_hum_out) AS max_hum_out,
maxvalue(l.trip_batt_charge) AS max_stateofcharge,
maxvalue(l.trip_batt_voltage) AS max_voltage,
maxvalue(l.trip_solar_voltage) AS max_solar_voltage,
maxvalue(l.trip_solar_power) AS max_solar_power,
maxvalue(l.trip_tank_level) AS max_tank_level,
twavg(l.trip_sog) AS avg_sog,
twavg(l.trip_tws) AS avg_tws,
twavg(l.trip_twd) AS avg_twd,
twavg(l.trip_depth) AS avg_depth,
twavg(l.trip_temp_water) AS avg_temp_water,
twavg(l.trip_temp_out) AS avg_temp_out,
twavg(l.trip_pres_out) AS avg_pres_out,
twavg(l.trip_hum_out) AS avg_hum_out,
twavg(l.trip_batt_charge) AS avg_stateofcharge,
twavg(l.trip_batt_voltage) AS avg_voltage,
twavg(l.trip_solar_voltage) AS avg_solar_voltage,
twavg(l.trip_solar_power) AS avg_solar_power,
twavg(l.trip_tank_level) AS avg_tank_level,
(trajectory(l.trip))::geometry AS track_geog,
l.extra,
l._to_moorage_id,
l._from_moorage_id,
(l.extra -> 'polar'::text) AS polar,
(l.user_data -> 'images'::text) AS images,
(l.user_data -> 'tags'::text) AS tags,
(l.user_data -> 'observations'::text) AS observations,
CASE
WHEN (jsonb_array_length((l.user_data -> 'images'::text)) > 0) THEN true
ELSE false
END AS has_images
FROM api.logbook l
WHERE ((l._to_time IS NOT NULL) AND (l.trip IS NOT NULL))
ORDER BY l._from_time DESC) tbl
)
Columns
| Name | Type | Default | Nullable |
|---|---|---|---|
| geojson | jsonb | true | |
| id | integer | true | |
| name | text | true | |
| starttimestamp | timestamp with time zone | true |
Referenced Tables
| Name | Columns | Comment | Type |
|---|---|---|---|
| api.logbook | 42 | Stores generated logbook | BASE TABLE |
Relations
erDiagram
"api.logs_geojson_view" {
jsonb geojson ""
integer id ""
text name ""
timestamp_with_time_zone starttimestamp ""
}
Generated by tbls
api.logs_view
Description
Logs web view
Table Definition
CREATE VIEW logs_view AS (
SELECT id,
name,
_from AS "from",
_from_time AS started,
_to AS "to",
_to_time AS ended,
distance,
duration,
_from_moorage_id,
_to_moorage_id,
(user_data -> 'tags'::text) AS tags
FROM api.logbook l
WHERE ((name IS NOT NULL) AND (_to_time IS NOT NULL))
ORDER BY _from_time DESC
)
Columns
| Name | Type | Default | Nullable |
|---|---|---|---|
| _from_moorage_id | integer | true | |
| _to_moorage_id | integer | true | |
| distance | numeric | true | |
| duration | interval | true | |
| ended | timestamp with time zone | true | |
| from | text | true | |
| id | integer | true | |
| name | text | true | |
| started | timestamp with time zone | true | |
| tags | jsonb | true | |
| to | text | true |
Referenced Tables
| Name | Columns | Comment | Type |
|---|---|---|---|
| api.logbook | 42 | Stores generated logbook | BASE TABLE |
Relations
erDiagram
"api.logs_view" {
integer _from_moorage_id ""
integer _to_moorage_id ""
numeric distance ""
interval duration ""
timestamp_with_time_zone ended ""
text from ""
integer id ""
text name ""
timestamp_with_time_zone started ""
jsonb tags ""
text to ""
}
Generated by tbls
api.metadata
Description
Stores metadata received from vessel, aka signalk plugin
Columns
| Name | Type | Default | Nullable | Children | Parents | Comment |
|---|---|---|---|---|---|---|
| active | boolean | true | true | trigger monitor online/offline | ||
| available_keys | jsonb | true | Signalk paths with unit for custom mapping | |||
| beam | double precision | true | ||||
| configuration | jsonb | true | User-defined Signalk path mapping for metrics | |||
| created_at | timestamp with time zone | now() | false | |||
| height | double precision | true | ||||
| ip | text | true | Store vessel ip address | |||
| length | double precision | true | ||||
| mmsi | text | true | Maritime Mobile Service Identity (MMSI) number associated with the vessel, link to public.mid | |||
| name | text | true | ||||
| platform | text | true | ||||
| plugin_version | text | false | ||||
| ship_type | numeric | true | Type of ship associated with the vessel, link to public.aistypes | |||
| signalk_version | text | false | ||||
| time | timestamp with time zone | false | ||||
| updated_at | timestamp with time zone | now() | false | |||
| user_data | jsonb | ‘{}’::jsonb | true | User-defined data including vessel polar (theoretical performance), make/model, and preferences | ||
| vessel_id | text | current_setting(‘vessel.id’::text, false) | false | api.logbook api.metrics api.moorages api.stays | auth.vessels | Link auth.vessels with api.metadata via FOREIGN KEY and REFERENCES |
Constraints
| Name | Type | Definition | Comment |
|---|---|---|---|
| metadata_created_at_not_null | n | NOT NULL created_at | |
| metadata_pkey | PRIMARY KEY | PRIMARY KEY (vessel_id) | |
| metadata_plugin_version_not_null | n | NOT NULL plugin_version | |
| metadata_signalk_version_not_null | n | NOT NULL signalk_version | |
| metadata_time_not_null | n | NOT NULL “time” | |
| metadata_updated_at_not_null | n | NOT NULL updated_at | |
| metadata_vessel_id_fkey | FOREIGN KEY | FOREIGN KEY (vessel_id) REFERENCES auth.vessels(vessel_id) ON DELETE RESTRICT | Link api.metadata with auth.vessels via vessel_id using FOREIGN KEY and REFERENCES |
| metadata_vessel_id_key | UNIQUE | UNIQUE (vessel_id) | |
| metadata_vessel_id_not_null | n | NOT NULL vessel_id |
Indexes
| Name | Definition |
|---|---|
| metadata_pkey | CREATE UNIQUE INDEX metadata_pkey ON api.metadata USING btree (vessel_id) |
| metadata_user_data_idx | CREATE INDEX metadata_user_data_idx ON api.metadata USING gin (user_data) |
| metadata_vessel_id_key | CREATE UNIQUE INDEX metadata_vessel_id_key ON api.metadata USING btree (vessel_id) |
Triggers
| Name | Definition | Comment |
|---|---|---|
| metadata_autodiscovery_trigger | CREATE TRIGGER metadata_autodiscovery_trigger AFTER INSERT ON api.metadata FOR EACH ROW EXECUTE FUNCTION metadata_autodiscovery_trigger_fn() | AFTER INSERT ON api.metadata run function metadata_autodiscovery_trigger_fn for later signalk mapping provisioning on new vessel |
| metadata_grafana_trigger | CREATE TRIGGER metadata_grafana_trigger AFTER INSERT ON api.metadata FOR EACH ROW EXECUTE FUNCTION metadata_grafana_trigger_fn() | AFTER INSERT ON api.metadata run function metadata_grafana_trigger_fn for later grafana provisioning on new vessel |
| metadata_moddatetime | CREATE TRIGGER metadata_moddatetime BEFORE UPDATE ON api.metadata FOR EACH ROW EXECUTE FUNCTION moddatetime(‘updated_at’) | Automatic update of updated_at on table modification |
| metadata_update_configuration_trigger | CREATE TRIGGER metadata_update_configuration_trigger BEFORE UPDATE ON api.metadata FOR EACH ROW EXECUTE FUNCTION update_metadata_configuration_trigger_fn() | BEFORE UPDATE ON api.metadata run function api.update_metadata_configuration tp update the configuration field with current date in ISO format |
| metadata_update_user_data_trigger | CREATE TRIGGER metadata_update_user_data_trigger BEFORE UPDATE ON api.metadata FOR EACH ROW EXECUTE FUNCTION update_metadata_userdata_added_at_trigger_fn() | BEFORE UPDATE ON api.metadata run function public.update_metadata_userdata_added_at_trigger_fn to update the user_data field with current date in ISO format when polar or images change |
| metadata_upsert_trigger | CREATE TRIGGER metadata_upsert_trigger BEFORE INSERT OR UPDATE ON api.metadata FOR EACH ROW EXECUTE FUNCTION metadata_upsert_trigger_fn() | BEFORE INSERT OR UPDATE ON api.metadata run function metadata_upsert_trigger_fn |
Relations
erDiagram
"api.metadata" |o--|| "auth.vessels" : "FOREIGN KEY (vessel_id) REFERENCES auth.vessels(vessel_id) ON DELETE RESTRICT"
"auth.vessels" }o--|| "auth.accounts" : "FOREIGN KEY (owner_email) REFERENCES auth.accounts(email) ON DELETE RESTRICT"
"api.logbook" }o--|| "api.metadata" : "FOREIGN KEY (vessel_id) REFERENCES api.metadata(vessel_id) ON DELETE RESTRICT"
"api.logbook" }o--o| "api.moorages" : "FOREIGN KEY (_from_moorage_id) REFERENCES api.moorages(id) ON DELETE RESTRICT"
"api.logbook" }o--o| "api.moorages" : "FOREIGN KEY (_to_moorage_id) REFERENCES api.moorages(id) ON DELETE RESTRICT"
"api.metrics" }o--|| "api.metadata" : "FOREIGN KEY (vessel_id) REFERENCES api.metadata(vessel_id) ON DELETE RESTRICT"
"api.moorages" }o--|| "api.metadata" : "FOREIGN KEY (vessel_id) REFERENCES api.metadata(vessel_id) ON DELETE RESTRICT"
"api.stays" }o--o| "api.moorages" : "FOREIGN KEY (moorage_id) REFERENCES api.moorages(id) ON DELETE RESTRICT"
"api.moorages" }o--o| "api.stays_at" : "FOREIGN KEY (stay_code) REFERENCES api.stays_at(stay_code) ON DELETE RESTRICT"
"api.stays" }o--|| "api.metadata" : "FOREIGN KEY (vessel_id) REFERENCES api.metadata(vessel_id) ON DELETE RESTRICT"
"api.stays" }o--o| "api.stays_at" : "FOREIGN KEY (stay_code) REFERENCES api.stays_at(stay_code) ON DELETE RESTRICT"
"api.metadata" {
boolean active "trigger monitor online/offline"
jsonb available_keys "Signalk paths with unit for custom mapping"
double_precision beam ""
jsonb configuration "User-defined Signalk path mapping for metrics"
timestamp_with_time_zone created_at ""
double_precision height ""
text ip "Store vessel ip address"
double_precision length ""
text mmsi "Maritime Mobile Service Identity (MMSI) number associated with the vessel, link to public.mid"
text name ""
text platform ""
text plugin_version ""
numeric ship_type "Type of ship associated with the vessel, link to public.aistypes"
text signalk_version ""
timestamp_with_time_zone time ""
timestamp_with_time_zone updated_at ""
jsonb user_data "User-defined data including vessel polar (theoretical performance), make/model, and preferences"
text vessel_id FK "Link auth.vessels with api.metadata via FOREIGN KEY and REFERENCES"
}
"auth.vessels" {
timestamp_with_time_zone created_at ""
numeric mmsi "MMSI can be optional but if present must be a valid one and unique but must be in numeric range between 100000000 and 800000000"
text name ""
citext owner_email FK ""
name role ""
timestamp_with_time_zone updated_at ""
text vessel_id ""
}
"auth.accounts" {
timestamp_with_time_zone connected_at ""
timestamp_with_time_zone created_at ""
citext email ""
text first "User first name with CONSTRAINT CHECK"
integer id ""
text last "User last name with CONSTRAINT CHECK"
text pass ""
jsonb preferences ""
name role ""
timestamp_with_time_zone updated_at ""
text user_id ""
}
"api.logbook" {
text _from "Name of the location where the log started, usually a moorage name"
double_precision _from_lat ""
double_precision _from_lng ""
integer _from_moorage_id FK "Link api.moorages with api.logbook via FOREIGN KEY and REFERENCES"
timestamp_with_time_zone _from_time ""
text _to "Name of the location where the log ended, usually a moorage name"
double_precision _to_lat ""
double_precision _to_lng ""
integer _to_moorage_id FK "Link api.moorages with api.logbook via FOREIGN KEY and REFERENCES"
timestamp_with_time_zone _to_time ""
boolean active ""
double_precision avg_speed "avg speed in knots"
numeric distance "Distance in Nautical Miles converted mobilitydb meters to NM"
interval duration "Duration in ISO 8601 format"
jsonb extra "Computed SignalK metrics such as runtime, current level, etc."
integer id ""
double_precision max_speed "max speed in knots"
double_precision max_wind_speed "true wind speed converted in knots, m/s from signalk plugin"
text name ""
text notes ""
tgeogpoint trip "MobilityDB trajectory, speed in m/s, distance in meters"
tfloat trip_awa "AWA (Apparent Wind Angle) in degrees converted from radians by signalk plugin"
tfloat trip_aws "AWS (Apparent Wind Speed), windSpeedApparent in knots converted by signalk plugin"
tfloat trip_batt_charge "Battery Charge"
tfloat trip_batt_voltage "Battery Voltage"
tfloat trip_cog "COG - Course Over Ground True in degrees converted from radians by signalk plugin"
tfloat trip_depth "Depth in meters, raw from signalk plugin"
tfloat trip_heading "Heading True in degrees converted from radians, raw from signalk plugin"
tfloat trip_hum_out "Humidity outside"
ttext trip_notes ""
tfloat trip_pres_out "Pressure outside"
tfloat trip_sog "SOG - Speed Over Ground in knots converted by signalk plugin"
tfloat trip_solar_power "solar powerPanel"
tfloat trip_solar_voltage "solar voltage"
ttext trip_status ""
tfloat trip_tank_level "Tank currentLevel"
tfloat trip_temp_out "Temperature outside in Kelvin, raw from signalk plugin"
tfloat trip_temp_water "Temperature water in Kelvin, raw from signalk plugin"
tfloat trip_twd "TWD - True Wind Direction in degrees converted from radians, raw from signalk plugin"
tfloat trip_tws "TWS - True Wind Speed in knots converted from m/s, raw from signalk plugin"
jsonb user_data "User-defined data Log-specific data including actual tags, observations, images and custom fields"
text vessel_id FK "Unique identifier for the vessel associated with the api.metadata entry"
}
"api.moorages" {
text country ""
geography_Point_4326_ geog "postgis geography type default SRID 4326 Unit: degres"
boolean home_flag ""
integer id ""
double_precision latitude ""
double_precision longitude ""
text name ""
jsonb nominatim "Output of the nominatim reverse geocoding service, see https://nominatim.org/release-docs/develop/api/Reverse/"
text notes ""
jsonb overpass "Output of the overpass API, see https://wiki.openstreetmap.org/wiki/Overpass_API"
integer stay_code FK "Link api.stays_at with api.moorages via FOREIGN KEY and REFERENCES"
jsonb user_data "User-defined data Mooring-specific data including images and custom fields"
text vessel_id FK "Unique identifier for the vessel associated with the api.metadata entry"
}
"api.metrics" {
double_precision anglespeedapparent ""
text client_id "Deprecated client_id to be removed"
double_precision courseovergroundtrue ""
double_precision latitude "With CONSTRAINT but allow NULL value to be ignored silently by trigger"
double_precision longitude "With CONSTRAINT but allow NULL value to be ignored silently by trigger"
jsonb metrics ""
double_precision speedoverground ""
text status ""
timestamp_with_time_zone time ""
text vessel_id FK "Unique identifier for the vessel associated with the api.metadata entry"
double_precision windspeedapparent ""
}
"api.stays" {
boolean active ""
timestamp_with_time_zone arrived ""
timestamp_with_time_zone departed ""
interval duration "Best to use standard ISO 8601"
geography_Point_4326_ geog "postgis geography type default SRID 4326 Unit: degres"
integer id ""
double_precision latitude ""
double_precision longitude ""
integer moorage_id FK "Link api.moorages with api.stays via FOREIGN KEY and REFERENCES"
text name ""
text notes ""
integer stay_code FK "Link api.stays_at with api.stays via FOREIGN KEY and REFERENCES"
jsonb user_data "User-defined data Stay-specific data including images and custom fields"
text vessel_id FK "Unique identifier for the vessel associated with the api.metadata entry"
}
"api.stays_at" {
text description ""
integer stay_code ""
}
Generated by tbls
api.metrics
Description
Stores metrics from vessel
Columns
| Name | Type | Default | Nullable | Parents | Comment |
|---|---|---|---|---|---|
| anglespeedapparent | double precision | true | |||
| client_id | text | true | Deprecated client_id to be removed | ||
| courseovergroundtrue | double precision | true | |||
| latitude | double precision | true | With CONSTRAINT but allow NULL value to be ignored silently by trigger | ||
| longitude | double precision | true | With CONSTRAINT but allow NULL value to be ignored silently by trigger | ||
| metrics | jsonb | true | |||
| speedoverground | double precision | true | |||
| status | text | true | |||
| time | timestamp with time zone | false | |||
| vessel_id | text | false | api.metadata | Unique identifier for the vessel associated with the api.metadata entry | |
| windspeedapparent | double precision | true |
Constraints
| Name | Type | Definition | Comment |
|---|---|---|---|
| metrics_pkey | PRIMARY KEY | PRIMARY KEY (“time”, vessel_id) | |
| metrics_time_not_null | n | NOT NULL “time” | |
| metrics_vessel_id_fkey | FOREIGN KEY | FOREIGN KEY (vessel_id) REFERENCES api.metadata(vessel_id) ON DELETE RESTRICT | Link api.metrics api.metadata via vessel_id using FOREIGN KEY and REFERENCES |
| metrics_vessel_id_not_null | n | NOT NULL vessel_id |
Indexes
| Name | Definition |
|---|---|
| metrics_metrics_idx | CREATE INDEX metrics_metrics_idx ON api.metrics USING gin (metrics) |
| metrics_pkey | CREATE UNIQUE INDEX metrics_pkey ON api.metrics USING btree (“time”, vessel_id) |
| metrics_status_time_idx | CREATE INDEX metrics_status_time_idx ON api.metrics USING btree (status, “time” DESC) |
| metrics_time_idx | CREATE INDEX metrics_time_idx ON api.metrics USING btree (“time” DESC) |
| metrics_vessel_id_time_idx | CREATE INDEX metrics_vessel_id_time_idx ON api.metrics USING btree (vessel_id, “time” DESC) |
Triggers
| Name | Definition | Comment |
|---|---|---|
| metrics_trigger | CREATE TRIGGER metrics_trigger BEFORE INSERT ON api.metrics FOR EACH ROW EXECUTE FUNCTION metrics_trigger_fn() | BEFORE INSERT ON api.metrics run function metrics_trigger_fn Validates: - Temporal anomalies (future timestamps, time jumps) - Coordinate validity - Generates pre_logbook and new_stay events |
Relations
erDiagram
"api.metrics" }o--|| "api.metadata" : "FOREIGN KEY (vessel_id) REFERENCES api.metadata(vessel_id) ON DELETE RESTRICT"
"api.metadata" |o--|| "auth.vessels" : "FOREIGN KEY (vessel_id) REFERENCES auth.vessels(vessel_id) ON DELETE RESTRICT"
"api.logbook" }o--|| "api.metadata" : "FOREIGN KEY (vessel_id) REFERENCES api.metadata(vessel_id) ON DELETE RESTRICT"
"api.moorages" }o--|| "api.metadata" : "FOREIGN KEY (vessel_id) REFERENCES api.metadata(vessel_id) ON DELETE RESTRICT"
"api.stays" }o--|| "api.metadata" : "FOREIGN KEY (vessel_id) REFERENCES api.metadata(vessel_id) ON DELETE RESTRICT"
"api.metrics" {
double_precision anglespeedapparent ""
text client_id "Deprecated client_id to be removed"
double_precision courseovergroundtrue ""
double_precision latitude "With CONSTRAINT but allow NULL value to be ignored silently by trigger"
double_precision longitude "With CONSTRAINT but allow NULL value to be ignored silently by trigger"
jsonb metrics ""
double_precision speedoverground ""
text status ""
timestamp_with_time_zone time ""
text vessel_id FK "Unique identifier for the vessel associated with the api.metadata entry"
double_precision windspeedapparent ""
}
"api.metadata" {
boolean active "trigger monitor online/offline"
jsonb available_keys "Signalk paths with unit for custom mapping"
double_precision beam ""
jsonb configuration "User-defined Signalk path mapping for metrics"
timestamp_with_time_zone created_at ""
double_precision height ""
text ip "Store vessel ip address"
double_precision length ""
text mmsi "Maritime Mobile Service Identity (MMSI) number associated with the vessel, link to public.mid"
text name ""
text platform ""
text plugin_version ""
numeric ship_type "Type of ship associated with the vessel, link to public.aistypes"
text signalk_version ""
timestamp_with_time_zone time ""
timestamp_with_time_zone updated_at ""
jsonb user_data "User-defined data including vessel polar (theoretical performance), make/model, and preferences"
text vessel_id FK "Link auth.vessels with api.metadata via FOREIGN KEY and REFERENCES"
}
"auth.vessels" {
timestamp_with_time_zone created_at ""
numeric mmsi "MMSI can be optional but if present must be a valid one and unique but must be in numeric range between 100000000 and 800000000"
text name ""
citext owner_email FK ""
name role ""
timestamp_with_time_zone updated_at ""
text vessel_id ""
}
"api.logbook" {
text _from "Name of the location where the log started, usually a moorage name"
double_precision _from_lat ""
double_precision _from_lng ""
integer _from_moorage_id FK "Link api.moorages with api.logbook via FOREIGN KEY and REFERENCES"
timestamp_with_time_zone _from_time ""
text _to "Name of the location where the log ended, usually a moorage name"
double_precision _to_lat ""
double_precision _to_lng ""
integer _to_moorage_id FK "Link api.moorages with api.logbook via FOREIGN KEY and REFERENCES"
timestamp_with_time_zone _to_time ""
boolean active ""
double_precision avg_speed "avg speed in knots"
numeric distance "Distance in Nautical Miles converted mobilitydb meters to NM"
interval duration "Duration in ISO 8601 format"
jsonb extra "Computed SignalK metrics such as runtime, current level, etc."
integer id ""
double_precision max_speed "max speed in knots"
double_precision max_wind_speed "true wind speed converted in knots, m/s from signalk plugin"
text name ""
text notes ""
tgeogpoint trip "MobilityDB trajectory, speed in m/s, distance in meters"
tfloat trip_awa "AWA (Apparent Wind Angle) in degrees converted from radians by signalk plugin"
tfloat trip_aws "AWS (Apparent Wind Speed), windSpeedApparent in knots converted by signalk plugin"
tfloat trip_batt_charge "Battery Charge"
tfloat trip_batt_voltage "Battery Voltage"
tfloat trip_cog "COG - Course Over Ground True in degrees converted from radians by signalk plugin"
tfloat trip_depth "Depth in meters, raw from signalk plugin"
tfloat trip_heading "Heading True in degrees converted from radians, raw from signalk plugin"
tfloat trip_hum_out "Humidity outside"
ttext trip_notes ""
tfloat trip_pres_out "Pressure outside"
tfloat trip_sog "SOG - Speed Over Ground in knots converted by signalk plugin"
tfloat trip_solar_power "solar powerPanel"
tfloat trip_solar_voltage "solar voltage"
ttext trip_status ""
tfloat trip_tank_level "Tank currentLevel"
tfloat trip_temp_out "Temperature outside in Kelvin, raw from signalk plugin"
tfloat trip_temp_water "Temperature water in Kelvin, raw from signalk plugin"
tfloat trip_twd "TWD - True Wind Direction in degrees converted from radians, raw from signalk plugin"
tfloat trip_tws "TWS - True Wind Speed in knots converted from m/s, raw from signalk plugin"
jsonb user_data "User-defined data Log-specific data including actual tags, observations, images and custom fields"
text vessel_id FK "Unique identifier for the vessel associated with the api.metadata entry"
}
"api.moorages" {
text country ""
geography_Point_4326_ geog "postgis geography type default SRID 4326 Unit: degres"
boolean home_flag ""
integer id ""
double_precision latitude ""
double_precision longitude ""
text name ""
jsonb nominatim "Output of the nominatim reverse geocoding service, see https://nominatim.org/release-docs/develop/api/Reverse/"
text notes ""
jsonb overpass "Output of the overpass API, see https://wiki.openstreetmap.org/wiki/Overpass_API"
integer stay_code FK "Link api.stays_at with api.moorages via FOREIGN KEY and REFERENCES"
jsonb user_data "User-defined data Mooring-specific data including images and custom fields"
text vessel_id FK "Unique identifier for the vessel associated with the api.metadata entry"
}
"api.stays" {
boolean active ""
timestamp_with_time_zone arrived ""
timestamp_with_time_zone departed ""
interval duration "Best to use standard ISO 8601"
geography_Point_4326_ geog "postgis geography type default SRID 4326 Unit: degres"
integer id ""
double_precision latitude ""
double_precision longitude ""
integer moorage_id FK "Link api.moorages with api.stays via FOREIGN KEY and REFERENCES"
text name ""
text notes ""
integer stay_code FK "Link api.stays_at with api.stays via FOREIGN KEY and REFERENCES"
jsonb user_data "User-defined data Stay-specific data including images and custom fields"
text vessel_id FK "Unique identifier for the vessel associated with the api.metadata entry"
}
Generated by tbls
api.monitoring_humidity
Description
Monitoring environment.%.humidity web view
Table Definition
CREATE VIEW monitoring_humidity AS (
SELECT m."time",
jsonb_each_text.key,
jsonb_each_text.value
FROM api.metrics m,
LATERAL jsonb_each_text(m.metrics) jsonb_each_text(key, value)
WHERE ((jsonb_each_text.key ~~* 'environment.%.humidity'::text) OR (jsonb_each_text.key ~~* 'environment.%.relativeHumidity'::text))
ORDER BY m."time" DESC
)
Columns
| Name | Type | Default | Nullable |
|---|---|---|---|
| key | text | true | |
| time | timestamp with time zone | true | |
| value | text | true |
Referenced Tables
| Name | Columns | Comment | Type |
|---|---|---|---|
| api.metrics | 11 | Stores metrics from vessel | BASE TABLE |
Relations
erDiagram
"api.monitoring_humidity" {
text key ""
timestamp_with_time_zone time ""
text value ""
}
Generated by tbls
api.monitoring_live
Description
Dynamic Monitoring web view
Table Definition
CREATE VIEW monitoring_live AS (
WITH pressure AS (
SELECT json_agg(json_build_object('time', sub.time_bucket, 'outsidePressure', sub.outsidepressure) ORDER BY sub.time_bucket) AS outsidepressurehistory
FROM ( SELECT time_bucket('PT10M'::interval, mt_1."time") AS time_bucket,
avg((COALESCE(((mt_1.metrics -> 'pressure'::text) ->> 'outside'::text), (mt_1.metrics ->> (md_1.configuration ->> 'outsidePressureKey'::text)), (mt_1.metrics ->> 'environment.outside.pressure'::text)))::double precision) AS outsidepressure
FROM (api.metrics mt_1
JOIN api.metadata md_1 ON ((md_1.vessel_id = mt_1.vessel_id)))
WHERE ((mt_1.vessel_id = current_setting('vessel.id'::text, false)) AND (mt_1."time" > ((now() AT TIME ZONE 'UTC'::text) - 'PT6H'::interval)))
GROUP BY (time_bucket('PT10M'::interval, mt_1."time"))
HAVING (avg((COALESCE(((mt_1.metrics -> 'pressure'::text) ->> 'outside'::text), (mt_1.metrics ->> (md_1.configuration ->> 'outsidePressureKey'::text)), (mt_1.metrics ->> 'environment.outside.pressure'::text)))::double precision) IS NOT NULL)) sub
)
SELECT mt."time",
((((now() AT TIME ZONE 'UTC'::text))::timestamp with time zone - mt."time") > 'PT1H10M'::interval) AS offline,
mt.metrics AS data,
jsonb_build_object('type', 'Feature', 'geometry', (st_asgeojson(st_makepoint(mt.longitude, mt.latitude)))::jsonb, 'properties', jsonb_build_object('name', current_setting('vessel.name'::text, false), 'latitude', mt.latitude, 'longitude', mt.longitude, 'time', mt."time", 'speedoverground', mt.speedoverground, 'windspeedapparent', mt.windspeedapparent, 'truewindspeed', (COALESCE(((mt.metrics -> 'wind'::text) ->> 'speed'::text), (mt.metrics ->> (md.configuration ->> 'windSpeedKey'::text)), (mt.metrics ->> 'environment.wind.speedTrue'::text)))::double precision, 'truewinddirection', (COALESCE(((mt.metrics -> 'wind'::text) ->> 'direction'::text), (mt.metrics ->> (md.configuration ->> 'windDirectionKey'::text)), (mt.metrics ->> 'environment.wind.directionTrue'::text)))::double precision, 'status', COALESCE(mt.status, NULL::text))) AS geojson,
current_setting('vessel.name'::text, false) AS name,
mt.status,
(COALESCE(((mt.metrics -> 'water'::text) ->> 'temperature'::text), (mt.metrics ->> (md.configuration ->> 'waterTemperatureKey'::text)), (mt.metrics ->> 'environment.water.temperature'::text)))::double precision AS watertemperature,
(COALESCE(((mt.metrics -> 'temperature'::text) ->> 'inside'::text), (mt.metrics ->> (md.configuration ->> 'insideTemperatureKey'::text)), (mt.metrics ->> 'environment.inside.temperature'::text)))::double precision AS insidetemperature,
(COALESCE(((mt.metrics -> 'temperature'::text) ->> 'outside'::text), (mt.metrics ->> (md.configuration ->> 'outsideTemperatureKey'::text)), (mt.metrics ->> 'environment.outside.temperature'::text)))::double precision AS outsidetemperature,
(COALESCE(((mt.metrics -> 'wind'::text) ->> 'speed'::text), (mt.metrics ->> (md.configuration ->> 'windSpeedKey'::text)), (mt.metrics ->> 'environment.wind.speedTrue'::text)))::double precision AS windspeedoverground,
(COALESCE(((mt.metrics -> 'wind'::text) ->> 'direction'::text), (mt.metrics ->> (md.configuration ->> 'windDirectionKey'::text)), (mt.metrics ->> 'environment.wind.directionTrue'::text)))::double precision AS winddirectiontrue,
(COALESCE(((mt.metrics -> 'humidity'::text) ->> 'inside'::text), (mt.metrics ->> (md.configuration ->> 'insideHumidityKey'::text)), (mt.metrics ->> 'environment.inside.relativeHumidity'::text), (mt.metrics ->> 'environment.inside.humidity'::text)))::double precision AS insidehumidity,
(COALESCE(((mt.metrics -> 'humidity'::text) ->> 'outside'::text), (mt.metrics ->> (md.configuration ->> 'outsideHumidityKey'::text)), (mt.metrics ->> 'environment.outside.relativeHumidity'::text), (mt.metrics ->> 'environment.outside.humidity'::text)))::double precision AS outsidehumidity,
(COALESCE(((mt.metrics -> 'pressure'::text) ->> 'outside'::text), (mt.metrics ->> (md.configuration ->> 'outsidePressureKey'::text)), (mt.metrics ->> 'environment.outside.pressure'::text)))::double precision AS outsidepressure,
(COALESCE(((mt.metrics -> 'pressure'::text) ->> 'inside'::text), (mt.metrics ->> (md.configuration ->> 'insidePressureKey'::text)), (mt.metrics ->> 'environment.inside.pressure'::text)))::double precision AS insidepressure,
(COALESCE(((mt.metrics -> 'battery'::text) ->> 'charge'::text), (mt.metrics ->> (md.configuration ->> 'stateOfChargeKey'::text)), (mt.metrics ->> 'electrical.batteries.House.capacity.stateOfCharge'::text)))::double precision AS batterycharge,
(COALESCE(((mt.metrics -> 'battery'::text) ->> 'voltage'::text), (mt.metrics ->> (md.configuration ->> 'voltageKey'::text)), (mt.metrics ->> 'electrical.batteries.House.voltage'::text)))::double precision AS batteryvoltage,
(COALESCE(((mt.metrics -> 'water'::text) ->> 'depth'::text), (mt.metrics ->> (md.configuration ->> 'depthKey'::text)), (mt.metrics ->> 'environment.depth.belowTransducer'::text)))::double precision AS depth,
(COALESCE(((mt.metrics -> 'solar'::text) ->> 'power'::text), (mt.metrics ->> (md.configuration ->> 'solarPowerKey'::text)), (mt.metrics ->> 'electrical.solar.Main.panelPower'::text)))::double precision AS solarpower,
(COALESCE(((mt.metrics -> 'solar'::text) ->> 'voltage'::text), (mt.metrics ->> (md.configuration ->> 'solarVoltageKey'::text)), (mt.metrics ->> 'electrical.solar.Main.panelVoltage'::text)))::double precision AS solarvoltage,
(COALESCE(((mt.metrics -> 'tank'::text) ->> 'level'::text), (mt.metrics ->> (md.configuration ->> 'tankLevelKey'::text)), (mt.metrics ->> 'tanks.fuel.0.currentLevel'::text)))::double precision AS tanklevel,
CASE
WHEN ((mt.status <> 'moored'::text) AND (mt.status <> 'anchored'::text)) THEN ( SELECT logbook_active_geojson_fn() AS logbook_active_geojson_fn)
WHEN ((mt.status = 'moored'::text) OR (mt.status = 'anchored'::text)) THEN ( SELECT stay_active_geojson_fn(mt."time") AS stay_active_geojson_fn)
ELSE NULL::jsonb
END AS live,
pressure.outsidepressurehistory
FROM ((api.metrics mt
JOIN api.metadata md ON ((md.vessel_id = mt.vessel_id)))
CROSS JOIN pressure)
ORDER BY mt."time" DESC
LIMIT 1
)
Columns
| Name | Type | Default | Nullable |
|---|---|---|---|
| batterycharge | double precision | true | |
| batteryvoltage | double precision | true | |
| data | jsonb | true | |
| depth | double precision | true | |
| geojson | jsonb | true | |
| insidehumidity | double precision | true | |
| insidepressure | double precision | true | |
| insidetemperature | double precision | true | |
| live | jsonb | true | |
| name | text | true | |
| offline | boolean | true | |
| outsidehumidity | double precision | true | |
| outsidepressure | double precision | true | |
| outsidepressurehistory | json | true | |
| outsidetemperature | double precision | true | |
| solarpower | double precision | true | |
| solarvoltage | double precision | true | |
| status | text | true | |
| tanklevel | double precision | true | |
| time | timestamp with time zone | true | |
| watertemperature | double precision | true | |
| winddirectiontrue | double precision | true | |
| windspeedoverground | double precision | true |
Referenced Tables
| Name | Columns | Comment | Type |
|---|---|---|---|
| api.metrics | 11 | Stores metrics from vessel | BASE TABLE |
| api.metadata | 18 | Stores metadata received from vessel, aka signalk plugin | BASE TABLE |
Relations
erDiagram
"api.monitoring_live" {
double_precision batterycharge ""
double_precision batteryvoltage ""
jsonb data ""
double_precision depth ""
jsonb geojson ""
double_precision insidehumidity ""
double_precision insidepressure ""
double_precision insidetemperature ""
jsonb live ""
text name ""
boolean offline ""
double_precision outsidehumidity ""
double_precision outsidepressure ""
json outsidepressurehistory ""
double_precision outsidetemperature ""
double_precision solarpower ""
double_precision solarvoltage ""
text status ""
double_precision tanklevel ""
timestamp_with_time_zone time ""
double_precision watertemperature ""
double_precision winddirectiontrue ""
double_precision windspeedoverground ""
}
Generated by tbls
api.monitoring_temperatures
Description
Monitoring environment.%.temperature web view
Table Definition
CREATE VIEW monitoring_temperatures AS (
SELECT m."time",
jsonb_each_text.key,
jsonb_each_text.value
FROM api.metrics m,
LATERAL jsonb_each_text(m.metrics) jsonb_each_text(key, value)
WHERE (jsonb_each_text.key ~~* 'environment.%.temperature'::text)
ORDER BY m."time" DESC
)
Columns
| Name | Type | Default | Nullable |
|---|---|---|---|
| key | text | true | |
| time | timestamp with time zone | true | |
| value | text | true |
Referenced Tables
| Name | Columns | Comment | Type |
|---|---|---|---|
| api.metrics | 11 | Stores metrics from vessel | BASE TABLE |
Relations
erDiagram
"api.monitoring_temperatures" {
text key ""
timestamp_with_time_zone time ""
text value ""
}
Generated by tbls
api.monitoring_view
Description
Monitoring static web view
Table Definition
CREATE VIEW monitoring_view AS (
SELECT "time",
((((now() AT TIME ZONE 'UTC'::text))::timestamp with time zone - "time") > 'PT1H10M'::interval) AS offline,
(metrics -> 'environment.water.temperature'::text) AS watertemperature,
(metrics -> 'environment.inside.temperature'::text) AS insidetemperature,
(metrics -> 'environment.outside.temperature'::text) AS outsidetemperature,
(metrics -> 'environment.wind.speedTrue'::text) AS windspeedoverground,
(metrics -> 'environment.wind.directionTrue'::text) AS winddirectiontrue,
(metrics -> 'environment.inside.relativeHumidity'::text) AS insidehumidity,
(metrics -> 'environment.outside.relativeHumidity'::text) AS outsidehumidity,
(metrics -> 'environment.outside.pressure'::text) AS outsidepressure,
(metrics -> 'environment.inside.pressure'::text) AS insidepressure,
(metrics -> 'electrical.batteries.House.capacity.stateOfCharge'::text) AS batterycharge,
(metrics -> 'electrical.batteries.House.voltage'::text) AS batteryvoltage,
(metrics -> 'environment.depth.belowTransducer'::text) AS depth,
jsonb_build_object('type', 'Feature', 'geometry', (st_asgeojson(st_makepoint(longitude, latitude)))::jsonb, 'properties', jsonb_build_object('name', current_setting('vessel.name'::text, false), 'latitude', latitude, 'longitude', longitude, 'time', "time", 'speedoverground', speedoverground, 'windspeedapparent', windspeedapparent, 'truewindspeed', COALESCE((metrics -> 'environment.wind.speedTrue'::text), NULL::jsonb), 'truewinddirection', COALESCE((metrics -> 'environment.wind.directionTrue'::text), NULL::jsonb), 'status', COALESCE(status, NULL::text))) AS geojson,
current_setting('vessel.name'::text, false) AS name,
status,
CASE
WHEN ((status <> 'moored'::text) AND (status <> 'anchored'::text)) THEN ( SELECT logbook_active_geojson_fn() AS logbook_active_geojson_fn)
WHEN ((status = 'moored'::text) OR (status = 'anchored'::text)) THEN ( SELECT stay_active_geojson_fn(m."time") AS stay_active_geojson_fn)
ELSE NULL::jsonb
END AS live
FROM api.metrics m
ORDER BY "time" DESC
LIMIT 1
)
Columns
| Name | Type | Default | Nullable |
|---|---|---|---|
| batterycharge | jsonb | true | |
| batteryvoltage | jsonb | true | |
| depth | jsonb | true | |
| geojson | jsonb | true | |
| insidehumidity | jsonb | true | |
| insidepressure | jsonb | true | |
| insidetemperature | jsonb | true | |
| live | jsonb | true | |
| name | text | true | |
| offline | boolean | true | |
| outsidehumidity | jsonb | true | |
| outsidepressure | jsonb | true | |
| outsidetemperature | jsonb | true | |
| status | text | true | |
| time | timestamp with time zone | true | |
| watertemperature | jsonb | true | |
| winddirectiontrue | jsonb | true | |
| windspeedoverground | jsonb | true |
Referenced Tables
| Name | Columns | Comment | Type |
|---|---|---|---|
| api.metrics | 11 | Stores metrics from vessel | BASE TABLE |
Relations
erDiagram
"api.monitoring_view" {
jsonb batterycharge ""
jsonb batteryvoltage ""
jsonb depth ""
jsonb geojson ""
jsonb insidehumidity ""
jsonb insidepressure ""
jsonb insidetemperature ""
jsonb live ""
text name ""
boolean offline ""
jsonb outsidehumidity ""
jsonb outsidepressure ""
jsonb outsidetemperature ""
text status ""
timestamp_with_time_zone time ""
jsonb watertemperature ""
jsonb winddirectiontrue ""
jsonb windspeedoverground ""
}
Generated by tbls
api.monitoring_view2
Description
Monitoring Last whatever data from json web view
Table Definition
CREATE VIEW monitoring_view2 AS (
SELECT key,
value
FROM jsonb_each(( SELECT m.metrics
FROM api.metrics m
ORDER BY m."time" DESC
LIMIT 1)) jsonb_each(key, value)
)
Columns
| Name | Type | Default | Nullable |
|---|---|---|---|
| key | text | true | |
| value | jsonb | true |
Referenced Tables
| Name | Columns | Comment | Type |
|---|---|---|---|
| jsonb_each | 0 | ||
| api.metrics | 11 | Stores metrics from vessel | BASE TABLE |
Relations
erDiagram
"api.monitoring_view2" {
text key ""
jsonb value ""
}
Generated by tbls
api.monitoring_view3
Description
Monitoring Timeseries whatever data from json web view
Table Definition
CREATE VIEW monitoring_view3 AS (
SELECT m."time",
jsonb_each_text.key,
jsonb_each_text.value
FROM api.metrics m,
LATERAL jsonb_each_text(m.metrics) jsonb_each_text(key, value)
ORDER BY m."time" DESC
)
Columns
| Name | Type | Default | Nullable |
|---|---|---|---|
| key | text | true | |
| time | timestamp with time zone | true | |
| value | text | true |
Referenced Tables
| Name | Columns | Comment | Type |
|---|---|---|---|
| api.metrics | 11 | Stores metrics from vessel | BASE TABLE |
Relations
erDiagram
"api.monitoring_view3" {
text key ""
timestamp_with_time_zone time ""
text value ""
}
Generated by tbls
api.monitoring_voltage
Description
Monitoring electrical.%.voltage web view
Table Definition
CREATE VIEW monitoring_voltage AS (
SELECT m."time",
jsonb_each_text.key,
jsonb_each_text.value
FROM api.metrics m,
LATERAL jsonb_each_text(m.metrics) jsonb_each_text(key, value)
WHERE (jsonb_each_text.key ~~* 'electrical.%.voltage'::text)
ORDER BY m."time" DESC
)
Columns
| Name | Type | Default | Nullable |
|---|---|---|---|
| key | text | true | |
| time | timestamp with time zone | true | |
| value | text | true |
Referenced Tables
| Name | Columns | Comment | Type |
|---|---|---|---|
| api.metrics | 11 | Stores metrics from vessel | BASE TABLE |
Relations
erDiagram
"api.monitoring_voltage" {
text key ""
timestamp_with_time_zone time ""
text value ""
}
Generated by tbls
api.moorage_view
Description
Moorage details web view
Table Definition
CREATE VIEW moorage_view AS (
WITH stay_details AS (
SELECT s.moorage_id,
s.arrived,
s.departed,
s.duration,
s.id AS stay_id,
first_value(s.id) OVER (PARTITION BY s.moorage_id ORDER BY s.arrived) AS first_seen_id,
first_value(s.id) OVER (PARTITION BY s.moorage_id ORDER BY s.departed DESC) AS last_seen_id
FROM api.stays s
WHERE (s.active = false)
), stay_summary AS (
SELECT stay_details.moorage_id,
min(stay_details.arrived) AS first_seen,
max(stay_details.departed) AS last_seen,
sum(stay_details.duration) AS total_duration,
count(*) AS stay_count,
max(stay_details.first_seen_id) AS first_seen_id,
max(stay_details.last_seen_id) AS last_seen_id
FROM stay_details
GROUP BY stay_details.moorage_id
), log_summary AS (
SELECT logs.moorage_id,
count(DISTINCT logs.id) AS log_count
FROM ( SELECT l_1._from_moorage_id AS moorage_id,
l_1.id
FROM api.logbook l_1
WHERE (l_1.active = false)
UNION ALL
SELECT l_1._to_moorage_id AS moorage_id,
l_1.id
FROM api.logbook l_1
WHERE (l_1.active = false)) logs
GROUP BY logs.moorage_id
)
SELECT m.id,
m.name,
sa.description AS default_stay,
sa.stay_code AS default_stay_id,
m.notes,
m.home_flag AS home,
m.geog,
m.latitude,
m.longitude,
COALESCE(l.log_count, (0)::bigint) AS logs_count,
COALESCE(ss.stay_count, (0)::bigint) AS stays_count,
COALESCE(ss.total_duration, 'PT0S'::interval) AS stays_sum_duration,
ss.first_seen AS stay_first_seen,
ss.last_seen AS stay_last_seen,
ss.first_seen_id AS stay_first_seen_id,
ss.last_seen_id AS stay_last_seen_id,
CASE
WHEN (jsonb_array_length((m.user_data -> 'images'::text)) > 0) THEN true
ELSE false
END AS has_images,
(m.user_data -> 'images'::text) AS images
FROM (((api.moorages m
JOIN api.stays_at sa ON ((m.stay_code = sa.stay_code)))
LEFT JOIN stay_summary ss ON ((m.id = ss.moorage_id)))
LEFT JOIN log_summary l ON ((m.id = l.moorage_id)))
WHERE (m.geog IS NOT NULL)
ORDER BY ss.total_duration DESC
)
Columns
| Name | Type | Default | Nullable |
|---|---|---|---|
| default_stay | text | true | |
| default_stay_id | integer | true | |
| geog | geography(Point,4326) | true | |
| has_images | boolean | true | |
| home | boolean | true | |
| id | integer | true | |
| images | jsonb | true | |
| latitude | double precision | true | |
| logs_count | bigint | true | |
| longitude | double precision | true | |
| name | text | true | |
| notes | text | true | |
| stay_first_seen | timestamp with time zone | true | |
| stay_first_seen_id | integer | true | |
| stay_last_seen | timestamp with time zone | true | |
| stay_last_seen_id | integer | true | |
| stays_count | bigint | true | |
| stays_sum_duration | interval | true |
Referenced Tables
| Name | Columns | Comment | Type |
|---|---|---|---|
| api.stays | 14 | Stores generated stays | BASE TABLE |
| api.logbook | 42 | Stores generated logbook | BASE TABLE |
| api.moorages | 13 | Stores generated moorages | BASE TABLE |
| api.stays_at | 2 | Stay Type | BASE TABLE |
| stay_summary | 0 | ||
| log_summary | 0 |
Relations
erDiagram
"api.moorage_view" {
text default_stay ""
integer default_stay_id ""
geography_Point_4326_ geog ""
boolean has_images ""
boolean home ""
integer id ""
jsonb images ""
double_precision latitude ""
bigint logs_count ""
double_precision longitude ""
text name ""
text notes ""
timestamp_with_time_zone stay_first_seen ""
integer stay_first_seen_id ""
timestamp_with_time_zone stay_last_seen ""
integer stay_last_seen_id ""
bigint stays_count ""
interval stays_sum_duration ""
}
Generated by tbls
api.moorages
Description
Stores generated moorages
Columns
| Name | Type | Default | Nullable | Children | Parents | Comment |
|---|---|---|---|---|---|---|
| country | text | true | ||||
| geog | geography(Point,4326) | true | postgis geography type default SRID 4326 Unit: degres | |||
| home_flag | boolean | false | true | |||
| id | integer | false | api.logbook api.stays | |||
| latitude | double precision | true | ||||
| longitude | double precision | true | ||||
| name | text | true | ||||
| nominatim | jsonb | true | Output of the nominatim reverse geocoding service, see https://nominatim.org/release-docs/develop/api/Reverse/ | |||
| notes | text | true | ||||
| overpass | jsonb | true | Output of the overpass API, see https://wiki.openstreetmap.org/wiki/Overpass_API | |||
| stay_code | integer | 1 | true | api.stays_at | Link api.stays_at with api.moorages via FOREIGN KEY and REFERENCES | |
| user_data | jsonb | ‘{}’::jsonb | true | User-defined data Mooring-specific data including images and custom fields | ||
| vessel_id | text | false | api.metadata | Unique identifier for the vessel associated with the api.metadata entry |
Constraints
| Name | Type | Definition | Comment |
|---|---|---|---|
| moorages_id_not_null | n | NOT NULL id | |
| moorages_pkey | PRIMARY KEY | PRIMARY KEY (id) | |
| moorages_stay_code_fkey | FOREIGN KEY | FOREIGN KEY (stay_code) REFERENCES api.stays_at(stay_code) ON DELETE RESTRICT | |
| moorages_vessel_id_fkey | FOREIGN KEY | FOREIGN KEY (vessel_id) REFERENCES api.metadata(vessel_id) ON DELETE RESTRICT | Link api.stays with api.metadata via vessel_id using FOREIGN KEY and REFERENCES |
| moorages_vessel_id_not_null | n | NOT NULL vessel_id |
Indexes
| Name | Definition |
|---|---|
| moorages_geog_idx | CREATE INDEX moorages_geog_idx ON api.moorages USING gist (geog) |
| moorages_geog_stay_code_idx | CREATE INDEX moorages_geog_stay_code_idx ON api.moorages USING btree (geog, stay_code) WHERE (geog IS NOT NULL) |
| moorages_pkey | CREATE UNIQUE INDEX moorages_pkey ON api.moorages USING btree (id) |
| moorages_stay_code_idx | CREATE INDEX moorages_stay_code_idx ON api.moorages USING btree (stay_code) |
| moorages_user_data_idx | CREATE INDEX moorages_user_data_idx ON api.moorages USING gin (user_data) |
| moorages_vessel_id_idx | CREATE INDEX moorages_vessel_id_idx ON api.moorages USING btree (vessel_id) |
Triggers
| Name | Definition | Comment |
|---|---|---|
| moorage_delete_trigger | CREATE TRIGGER moorage_delete_trigger BEFORE DELETE ON api.moorages FOR EACH ROW EXECUTE FUNCTION moorage_delete_trigger_fn() | Automatic delete logbook and stays reference when delete a moorage |
| moorage_update_trigger | CREATE TRIGGER moorage_update_trigger AFTER UPDATE ON api.moorages FOR EACH ROW EXECUTE FUNCTION moorage_update_trigger_fn() | Automatic update of name and stay_code on logbook and stays reference |
| moorages_update_user_data_trigger | CREATE TRIGGER moorages_update_user_data_trigger BEFORE UPDATE ON api.moorages FOR EACH ROW EXECUTE FUNCTION update_tbl_userdata_added_at_trigger_fn() | BEFORE UPDATE ON api.moorages run function public.update_tbl_userdata_added_at_trigger_fn to update the user_data field with current date in ISO format when polar or images change |
Relations
erDiagram
"api.logbook" }o--o| "api.moorages" : "FOREIGN KEY (_from_moorage_id) REFERENCES api.moorages(id) ON DELETE RESTRICT"
"api.logbook" }o--o| "api.moorages" : "FOREIGN KEY (_to_moorage_id) REFERENCES api.moorages(id) ON DELETE RESTRICT"
"api.logbook" }o--|| "api.metadata" : "FOREIGN KEY (vessel_id) REFERENCES api.metadata(vessel_id) ON DELETE RESTRICT"
"api.stays" }o--o| "api.moorages" : "FOREIGN KEY (moorage_id) REFERENCES api.moorages(id) ON DELETE RESTRICT"
"api.stays" }o--o| "api.stays_at" : "FOREIGN KEY (stay_code) REFERENCES api.stays_at(stay_code) ON DELETE RESTRICT"
"api.stays" }o--|| "api.metadata" : "FOREIGN KEY (vessel_id) REFERENCES api.metadata(vessel_id) ON DELETE RESTRICT"
"api.moorages" }o--o| "api.stays_at" : "FOREIGN KEY (stay_code) REFERENCES api.stays_at(stay_code) ON DELETE RESTRICT"
"api.moorages" }o--|| "api.metadata" : "FOREIGN KEY (vessel_id) REFERENCES api.metadata(vessel_id) ON DELETE RESTRICT"
"api.metadata" |o--|| "auth.vessels" : "FOREIGN KEY (vessel_id) REFERENCES auth.vessels(vessel_id) ON DELETE RESTRICT"
"api.metrics" }o--|| "api.metadata" : "FOREIGN KEY (vessel_id) REFERENCES api.metadata(vessel_id) ON DELETE RESTRICT"
"api.moorages" {
text country ""
geography_Point_4326_ geog "postgis geography type default SRID 4326 Unit: degres"
boolean home_flag ""
integer id ""
double_precision latitude ""
double_precision longitude ""
text name ""
jsonb nominatim "Output of the nominatim reverse geocoding service, see https://nominatim.org/release-docs/develop/api/Reverse/"
text notes ""
jsonb overpass "Output of the overpass API, see https://wiki.openstreetmap.org/wiki/Overpass_API"
integer stay_code FK "Link api.stays_at with api.moorages via FOREIGN KEY and REFERENCES"
jsonb user_data "User-defined data Mooring-specific data including images and custom fields"
text vessel_id FK "Unique identifier for the vessel associated with the api.metadata entry"
}
"api.logbook" {
text _from "Name of the location where the log started, usually a moorage name"
double_precision _from_lat ""
double_precision _from_lng ""
integer _from_moorage_id FK "Link api.moorages with api.logbook via FOREIGN KEY and REFERENCES"
timestamp_with_time_zone _from_time ""
text _to "Name of the location where the log ended, usually a moorage name"
double_precision _to_lat ""
double_precision _to_lng ""
integer _to_moorage_id FK "Link api.moorages with api.logbook via FOREIGN KEY and REFERENCES"
timestamp_with_time_zone _to_time ""
boolean active ""
double_precision avg_speed "avg speed in knots"
numeric distance "Distance in Nautical Miles converted mobilitydb meters to NM"
interval duration "Duration in ISO 8601 format"
jsonb extra "Computed SignalK metrics such as runtime, current level, etc."
integer id ""
double_precision max_speed "max speed in knots"
double_precision max_wind_speed "true wind speed converted in knots, m/s from signalk plugin"
text name ""
text notes ""
tgeogpoint trip "MobilityDB trajectory, speed in m/s, distance in meters"
tfloat trip_awa "AWA (Apparent Wind Angle) in degrees converted from radians by signalk plugin"
tfloat trip_aws "AWS (Apparent Wind Speed), windSpeedApparent in knots converted by signalk plugin"
tfloat trip_batt_charge "Battery Charge"
tfloat trip_batt_voltage "Battery Voltage"
tfloat trip_cog "COG - Course Over Ground True in degrees converted from radians by signalk plugin"
tfloat trip_depth "Depth in meters, raw from signalk plugin"
tfloat trip_heading "Heading True in degrees converted from radians, raw from signalk plugin"
tfloat trip_hum_out "Humidity outside"
ttext trip_notes ""
tfloat trip_pres_out "Pressure outside"
tfloat trip_sog "SOG - Speed Over Ground in knots converted by signalk plugin"
tfloat trip_solar_power "solar powerPanel"
tfloat trip_solar_voltage "solar voltage"
ttext trip_status ""
tfloat trip_tank_level "Tank currentLevel"
tfloat trip_temp_out "Temperature outside in Kelvin, raw from signalk plugin"
tfloat trip_temp_water "Temperature water in Kelvin, raw from signalk plugin"
tfloat trip_twd "TWD - True Wind Direction in degrees converted from radians, raw from signalk plugin"
tfloat trip_tws "TWS - True Wind Speed in knots converted from m/s, raw from signalk plugin"
jsonb user_data "User-defined data Log-specific data including actual tags, observations, images and custom fields"
text vessel_id FK "Unique identifier for the vessel associated with the api.metadata entry"
}
"api.metadata" {
boolean active "trigger monitor online/offline"
jsonb available_keys "Signalk paths with unit for custom mapping"
double_precision beam ""
jsonb configuration "User-defined Signalk path mapping for metrics"
timestamp_with_time_zone created_at ""
double_precision height ""
text ip "Store vessel ip address"
double_precision length ""
text mmsi "Maritime Mobile Service Identity (MMSI) number associated with the vessel, link to public.mid"
text name ""
text platform ""
text plugin_version ""
numeric ship_type "Type of ship associated with the vessel, link to public.aistypes"
text signalk_version ""
timestamp_with_time_zone time ""
timestamp_with_time_zone updated_at ""
jsonb user_data "User-defined data including vessel polar (theoretical performance), make/model, and preferences"
text vessel_id FK "Link auth.vessels with api.metadata via FOREIGN KEY and REFERENCES"
}
"api.stays" {
boolean active ""
timestamp_with_time_zone arrived ""
timestamp_with_time_zone departed ""
interval duration "Best to use standard ISO 8601"
geography_Point_4326_ geog "postgis geography type default SRID 4326 Unit: degres"
integer id ""
double_precision latitude ""
double_precision longitude ""
integer moorage_id FK "Link api.moorages with api.stays via FOREIGN KEY and REFERENCES"
text name ""
text notes ""
integer stay_code FK "Link api.stays_at with api.stays via FOREIGN KEY and REFERENCES"
jsonb user_data "User-defined data Stay-specific data including images and custom fields"
text vessel_id FK "Unique identifier for the vessel associated with the api.metadata entry"
}
"api.stays_at" {
text description ""
integer stay_code ""
}
"auth.vessels" {
timestamp_with_time_zone created_at ""
numeric mmsi "MMSI can be optional but if present must be a valid one and unique but must be in numeric range between 100000000 and 800000000"
text name ""
citext owner_email FK ""
name role ""
timestamp_with_time_zone updated_at ""
text vessel_id ""
}
"api.metrics" {
double_precision anglespeedapparent ""
text client_id "Deprecated client_id to be removed"
double_precision courseovergroundtrue ""
double_precision latitude "With CONSTRAINT but allow NULL value to be ignored silently by trigger"
double_precision longitude "With CONSTRAINT but allow NULL value to be ignored silently by trigger"
jsonb metrics ""
double_precision speedoverground ""
text status ""
timestamp_with_time_zone time ""
text vessel_id FK "Unique identifier for the vessel associated with the api.metadata entry"
double_precision windspeedapparent ""
}
Generated by tbls
api.moorages_geojson_view
Description
List moorages as geojson
Table Definition
CREATE VIEW moorages_geojson_view AS (
SELECT id,
name,
(st_asgeojson(m.*))::jsonb AS geojson
FROM ( SELECT m_1.id,
m_1.name,
m_1.default_stay,
m_1.default_stay_id,
m_1.notes,
m_1.home,
m_1.geog,
m_1.latitude,
m_1.longitude,
m_1.logs_count,
m_1.stays_count,
m_1.stays_sum_duration,
m_1.stay_first_seen,
m_1.stay_last_seen,
m_1.stay_first_seen_id,
m_1.stay_last_seen_id,
m_1.has_images,
m_1.images
FROM api.moorage_view m_1
WHERE (m_1.geog IS NOT NULL)) m
)
Columns
| Name | Type | Default | Nullable |
|---|---|---|---|
| geojson | jsonb | true | |
| id | integer | true | |
| name | text | true |
Referenced Tables
| Name | Columns | Comment | Type |
|---|---|---|---|
| api.moorage_view | 18 | Moorage details web view | VIEW |
Relations
erDiagram
"api.moorages_geojson_view" {
jsonb geojson ""
integer id ""
text name ""
}
Generated by tbls
api.moorages_stays_view
Description
Moorages stay listing web view
Table Definition
CREATE VIEW moorages_stays_view AS (
SELECT _to.name AS _to_name,
_to.id AS _to_id,
_to._to_time,
_from.id AS _from_id,
_from.name AS _from_name,
_from._from_time,
s.stay_code,
s.duration,
m.id,
m.name
FROM api.stays_at sa,
api.moorages m,
((api.stays s
LEFT JOIN api.logbook _from ON ((_from._from_time = s.departed)))
LEFT JOIN api.logbook _to ON ((_to._to_time = s.arrived)))
WHERE ((s.departed IS NOT NULL) AND (s.name IS NOT NULL) AND (s.stay_code = sa.stay_code) AND (s.moorage_id = m.id))
ORDER BY _to._to_time DESC
)
Columns
| Name | Type | Default | Nullable |
|---|---|---|---|
| _from_id | integer | true | |
| _from_name | text | true | |
| _from_time | timestamp with time zone | true | |
| _to_id | integer | true | |
| _to_name | text | true | |
| _to_time | timestamp with time zone | true | |
| duration | interval | true | |
| id | integer | true | |
| name | text | true | |
| stay_code | integer | true |
Referenced Tables
| Name | Columns | Comment | Type |
|---|---|---|---|
| api.stays_at | 2 | Stay Type | BASE TABLE |
| api.logbook | 42 | Stores generated logbook | BASE TABLE |
Relations
erDiagram
"api.moorages_stays_view" {
integer _from_id ""
text _from_name ""
timestamp_with_time_zone _from_time ""
integer _to_id ""
text _to_name ""
timestamp_with_time_zone _to_time ""
interval duration ""
integer id ""
text name ""
integer stay_code ""
}
Generated by tbls
api.moorages_view
Description
Moorages listing web view
Table Definition
CREATE VIEW moorages_view AS (
SELECT m.id,
m.name AS moorage,
sa.description AS default_stay,
sa.stay_code AS default_stay_id,
COALESCE(count(DISTINCT l.id), (0)::bigint) AS arrivals_departures,
COALESCE(sum(DISTINCT s.duration), 'PT0S'::interval) AS total_duration
FROM (((api.moorages m
JOIN api.stays_at sa ON ((m.stay_code = sa.stay_code)))
LEFT JOIN api.stays s ON (((m.id = s.moorage_id) AND (s.active = false))))
LEFT JOIN api.logbook l ON (((m.id = l._from_moorage_id) OR ((m.id = l._to_moorage_id) AND (l.active = false)))))
WHERE ((m.geog IS NOT NULL) AND (m.stay_code = sa.stay_code))
GROUP BY m.id, m.name, sa.description, sa.stay_code
ORDER BY COALESCE(sum(DISTINCT s.duration), 'PT0S'::interval) DESC
)
Columns
| Name | Type | Default | Nullable |
|---|---|---|---|
| arrivals_departures | bigint | true | |
| default_stay | text | true | |
| default_stay_id | integer | true | |
| id | integer | true | |
| moorage | text | true | |
| total_duration | interval | true |
Referenced Tables
| Name | Columns | Comment | Type |
|---|---|---|---|
| api.moorages | 13 | Stores generated moorages | BASE TABLE |
| api.stays_at | 2 | Stay Type | BASE TABLE |
| api.stays | 14 | Stores generated stays | BASE TABLE |
| api.logbook | 42 | Stores generated logbook | BASE TABLE |
Relations
erDiagram
"api.moorages_view" {
bigint arrivals_departures ""
text default_stay ""
integer default_stay_id ""
integer id ""
text moorage ""
interval total_duration ""
}
Generated by tbls
api.stays_explore_view
api.stats_logs_view
Description
Statistics Logs web view
Table Definition
CREATE VIEW stats_logs_view AS (
WITH meta AS (
SELECT m_1.name
FROM api.metadata m_1
), last_metric AS (
SELECT m_1."time"
FROM api.metrics m_1
ORDER BY m_1."time" DESC
LIMIT 1
), first_metric AS (
SELECT m_1."time"
FROM api.metrics m_1
ORDER BY m_1."time"
LIMIT 1
), logbook AS (
SELECT count(*) AS number_of_log_entries,
max(l_1.max_speed) AS max_speed,
max(l_1.max_wind_speed) AS max_wind_speed,
sum(l_1.distance) AS total_distance,
sum(l_1.duration) AS total_time_underway,
concat(max(l_1.distance), ' NM, ', max(l_1.duration), ' hours') AS longest_nonstop_sail
FROM api.logbook l_1
)
SELECT m.name,
fm."time" AS first,
lm."time" AS last,
l.number_of_log_entries,
l.max_speed,
l.max_wind_speed,
l.total_distance,
l.total_time_underway,
l.longest_nonstop_sail
FROM first_metric fm,
last_metric lm,
logbook l,
meta m
)
Columns
| Name | Type | Default | Nullable |
|---|---|---|---|
| first | timestamp with time zone | true | |
| last | timestamp with time zone | true | |
| longest_nonstop_sail | text | true | |
| max_speed | double precision | true | |
| max_wind_speed | double precision | true | |
| name | text | true | |
| number_of_log_entries | bigint | true | |
| total_distance | numeric | true | |
| total_time_underway | interval | true |
Referenced Tables
| Name | Columns | Comment | Type |
|---|---|---|---|
| api.metadata | 18 | Stores metadata received from vessel, aka signalk plugin | BASE TABLE |
| api.metrics | 11 | Stores metrics from vessel | BASE TABLE |
| api.logbook | 42 | Stores generated logbook | BASE TABLE |
| public.first_metric | 11 | VIEW |
Relations
erDiagram
"api.stats_logs_view" {
timestamp_with_time_zone first ""
timestamp_with_time_zone last ""
text longest_nonstop_sail ""
double_precision max_speed ""
double_precision max_wind_speed ""
text name ""
bigint number_of_log_entries ""
numeric total_distance ""
interval total_time_underway ""
}
Generated by tbls
api.stats_moorages_away_view
Description
Statistics Moorages Time Spent Away web view
Table Definition
CREATE VIEW stats_moorages_away_view AS (
SELECT sa.description,
sum(m.stays_sum_duration) AS time_spent_away_by
FROM api.moorage_view m,
api.stays_at sa
WHERE ((m.home IS FALSE) AND (m.default_stay_id = sa.stay_code))
GROUP BY m.default_stay_id, sa.description
ORDER BY m.default_stay_id
)
Columns
| Name | Type | Default | Nullable |
|---|---|---|---|
| description | text | true | |
| time_spent_away_by | interval | true |
Referenced Tables
| Name | Columns | Comment | Type |
|---|---|---|---|
| api.moorage_view | 18 | Moorage details web view | VIEW |
Relations
erDiagram
"api.stats_moorages_away_view" {
text description ""
interval time_spent_away_by ""
}
Generated by tbls
api.stats_moorages_view
Description
Statistics Moorages web view
Table Definition
CREATE VIEW stats_moorages_view AS (
WITH home_ports AS (
SELECT count(*) AS home_ports
FROM api.moorage_view m
WHERE (m.home IS TRUE)
), unique_moorage AS (
SELECT count(*) AS unique_moorage
FROM api.moorage_view m
), time_at_home_ports AS (
SELECT sum(m.stays_sum_duration) AS time_at_home_ports
FROM api.moorage_view m
WHERE (m.home IS TRUE)
), time_spent_away AS (
SELECT sum(m.stays_sum_duration) AS time_spent_away
FROM api.moorage_view m
WHERE (m.home IS FALSE)
)
SELECT home_ports.home_ports,
unique_moorage.unique_moorage AS unique_moorages,
time_at_home_ports.time_at_home_ports AS "time_spent_at_home_port(s)",
time_spent_away.time_spent_away
FROM home_ports,
unique_moorage,
time_at_home_ports,
time_spent_away
)
Columns
| Name | Type | Default | Nullable |
|---|---|---|---|
| home_ports | bigint | true | |
| time_spent_at_home_port(s) | interval | true | |
| time_spent_away | interval | true | |
| unique_moorages | bigint | true |
Referenced Tables
| Name | Columns | Comment | Type |
|---|---|---|---|
| api.moorage_view | 18 | Moorage details web view | VIEW |
Relations
erDiagram
"api.stats_moorages_view" {
bigint home_ports ""
interval time_spent_at_home_port(s) ""
interval time_spent_away ""
bigint unique_moorages ""
}
Generated by tbls
api.stay_view
Description
Stay web view
Table Definition
CREATE VIEW stay_view AS (
SELECT s.id,
s.name,
m.name AS moorage,
m.id AS moorage_id,
(s.departed - s.arrived) AS duration,
sa.description AS stayed_at,
sa.stay_code AS stayed_at_id,
s.arrived,
_from.id AS arrived_log_id,
_from._to_moorage_id AS arrived_from_moorage_id,
_from._to AS arrived_from_moorage_name,
s.departed,
_to.id AS departed_log_id,
_to._from_moorage_id AS departed_to_moorage_id,
_to._from AS departed_to_moorage_name,
s.notes,
CASE
WHEN (jsonb_array_length((s.user_data -> 'images'::text)) > 0) THEN true
ELSE false
END AS has_images,
(s.user_data -> 'images'::text) AS images
FROM ((((api.stays s
JOIN api.stays_at sa ON ((s.stay_code = sa.stay_code)))
JOIN api.moorages m ON ((s.moorage_id = m.id)))
LEFT JOIN api.logbook _from ON ((_from._from_time = s.departed)))
LEFT JOIN api.logbook _to ON ((_to._to_time = s.arrived)))
WHERE ((s.departed IS NOT NULL) AND (_from._to_moorage_id IS NOT NULL) AND (s.name IS NOT NULL))
ORDER BY s.arrived DESC
)
Columns
| Name | Type | Default | Nullable |
|---|---|---|---|
| arrived | timestamp with time zone | true | |
| arrived_from_moorage_id | integer | true | |
| arrived_from_moorage_name | text | true | |
| arrived_log_id | integer | true | |
| departed | timestamp with time zone | true | |
| departed_log_id | integer | true | |
| departed_to_moorage_id | integer | true | |
| departed_to_moorage_name | text | true | |
| duration | interval | true | |
| has_images | boolean | true | |
| id | integer | true | |
| images | jsonb | true | |
| moorage | text | true | |
| moorage_id | integer | true | |
| name | text | true | |
| notes | text | true | |
| stayed_at | text | true | |
| stayed_at_id | integer | true |
Referenced Tables
| Name | Columns | Comment | Type |
|---|---|---|---|
| api.stays | 14 | Stores generated stays | BASE TABLE |
| api.stays_at | 2 | Stay Type | BASE TABLE |
| api.moorages | 13 | Stores generated moorages | BASE TABLE |
| api.logbook | 42 | Stores generated logbook | BASE TABLE |
Relations
erDiagram
"api.stay_view" {
timestamp_with_time_zone arrived ""
integer arrived_from_moorage_id ""
text arrived_from_moorage_name ""
integer arrived_log_id ""
timestamp_with_time_zone departed ""
integer departed_log_id ""
integer departed_to_moorage_id ""
text departed_to_moorage_name ""
interval duration ""
boolean has_images ""
integer id ""
jsonb images ""
text moorage ""
integer moorage_id ""
text name ""
text notes ""
text stayed_at ""
integer stayed_at_id ""
}
Generated by tbls
api.stays
Description
Stores generated stays
Columns
| Name | Type | Default | Nullable | Parents | Comment |
|---|---|---|---|---|---|
| active | boolean | false | true | ||
| arrived | timestamp with time zone | false | |||
| departed | timestamp with time zone | true | |||
| duration | interval | true | Best to use standard ISO 8601 | ||
| geog | geography(Point,4326) | true | postgis geography type default SRID 4326 Unit: degres | ||
| id | integer | false | |||
| latitude | double precision | true | |||
| longitude | double precision | true | |||
| moorage_id | integer | true | api.moorages | Link api.moorages with api.stays via FOREIGN KEY and REFERENCES | |
| name | text | true | |||
| notes | text | true | |||
| stay_code | integer | 1 | true | api.stays_at | Link api.stays_at with api.stays via FOREIGN KEY and REFERENCES |
| user_data | jsonb | ‘{}’::jsonb | true | User-defined data Stay-specific data including images and custom fields | |
| vessel_id | text | false | api.metadata | Unique identifier for the vessel associated with the api.metadata entry |
Constraints
| Name | Type | Definition | Comment |
|---|---|---|---|
| stays_arrived_not_null | n | NOT NULL arrived | |
| stays_id_not_null | n | NOT NULL id | |
| stays_moorage_id_fkey | FOREIGN KEY | FOREIGN KEY (moorage_id) REFERENCES api.moorages(id) ON DELETE RESTRICT | |
| stays_pkey | PRIMARY KEY | PRIMARY KEY (id) | |
| stays_stay_code_fkey | FOREIGN KEY | FOREIGN KEY (stay_code) REFERENCES api.stays_at(stay_code) ON DELETE RESTRICT | |
| stays_vessel_id_fkey | FOREIGN KEY | FOREIGN KEY (vessel_id) REFERENCES api.metadata(vessel_id) ON DELETE RESTRICT | Link api.stays with api.metadata via vessel_id using FOREIGN KEY and REFERENCES |
| stays_vessel_id_not_null | n | NOT NULL vessel_id |
Indexes
| Name | Definition |
|---|---|
| stays_arrived_departed_idx | CREATE INDEX stays_arrived_departed_idx ON api.stays USING btree (arrived DESC, departed, stay_code, moorage_id, name) WHERE ((departed IS NOT NULL) AND (name IS NOT NULL)) |
| stays_arrived_idx | CREATE INDEX stays_arrived_idx ON api.stays USING btree (arrived) |
| stays_departed_arrived_idx | CREATE INDEX stays_departed_arrived_idx ON api.stays USING btree (departed, arrived DESC) WHERE ((departed IS NOT NULL) AND (name IS NOT NULL)) |
| stays_departed_id_idx | CREATE INDEX stays_departed_id_idx ON api.stays USING btree (departed) |
| stays_geog_idx | CREATE INDEX stays_geog_idx ON api.stays USING gist (geog) |
| stays_moorage_arrived_departed_idx | CREATE INDEX stays_moorage_arrived_departed_idx ON api.stays USING btree (moorage_id, arrived, departed, active) WHERE (active = false) |
| stays_moorage_arrived_idx | CREATE INDEX stays_moorage_arrived_idx ON api.stays USING btree (moorage_id, arrived DESC) WHERE (departed IS NOT NULL) |
| stays_moorage_duration_idx | CREATE INDEX stays_moorage_duration_idx ON api.stays USING btree (moorage_id, duration) WHERE (active = false) |
| stays_moorage_id_idx | CREATE INDEX stays_moorage_id_idx ON api.stays USING btree (moorage_id) |
| stays_pkey | CREATE UNIQUE INDEX stays_pkey ON api.stays USING btree (id) |
| stays_stay_code_idx | CREATE INDEX stays_stay_code_idx ON api.stays USING btree (stay_code) |
| stays_user_data_idx | CREATE INDEX stays_user_data_idx ON api.stays USING gin (user_data) |
| stays_vessel_arrived_idx | CREATE INDEX stays_vessel_arrived_idx ON api.stays USING btree (vessel_id, arrived DESC, departed DESC) INCLUDE (moorage_id, stay_code) |
| stays_vessel_id_idx | CREATE INDEX stays_vessel_id_idx ON api.stays USING btree (vessel_id) |
Triggers
| Name | Definition | Comment |
|---|---|---|
| stay_delete_trigger | CREATE TRIGGER stay_delete_trigger BEFORE DELETE ON api.stays FOR EACH ROW EXECUTE FUNCTION stay_delete_trigger_fn() | BEFORE DELETE ON api.stays run function public.stay_delete_trigger_fn to delete reference and stay_ext need to deleted. |
| stays_update_user_data_trigger | CREATE TRIGGER stays_update_user_data_trigger BEFORE UPDATE ON api.stays FOR EACH ROW EXECUTE FUNCTION update_tbl_userdata_added_at_trigger_fn() | BEFORE UPDATE ON api.stays run function public.update_tbl_userdata_added_at_trigger_fn to update the user_data field with current date in ISO format when polar or images change |
Relations
erDiagram
"api.stays" }o--o| "api.moorages" : "FOREIGN KEY (moorage_id) REFERENCES api.moorages(id) ON DELETE RESTRICT"
"api.logbook" }o--o| "api.moorages" : "FOREIGN KEY (_from_moorage_id) REFERENCES api.moorages(id) ON DELETE RESTRICT"
"api.logbook" }o--o| "api.moorages" : "FOREIGN KEY (_to_moorage_id) REFERENCES api.moorages(id) ON DELETE RESTRICT"
"api.moorages" }o--o| "api.stays_at" : "FOREIGN KEY (stay_code) REFERENCES api.stays_at(stay_code) ON DELETE RESTRICT"
"api.moorages" }o--|| "api.metadata" : "FOREIGN KEY (vessel_id) REFERENCES api.metadata(vessel_id) ON DELETE RESTRICT"
"api.stays" }o--o| "api.stays_at" : "FOREIGN KEY (stay_code) REFERENCES api.stays_at(stay_code) ON DELETE RESTRICT"
"api.stays" }o--|| "api.metadata" : "FOREIGN KEY (vessel_id) REFERENCES api.metadata(vessel_id) ON DELETE RESTRICT"
"api.metadata" |o--|| "auth.vessels" : "FOREIGN KEY (vessel_id) REFERENCES auth.vessels(vessel_id) ON DELETE RESTRICT"
"api.logbook" }o--|| "api.metadata" : "FOREIGN KEY (vessel_id) REFERENCES api.metadata(vessel_id) ON DELETE RESTRICT"
"api.metrics" }o--|| "api.metadata" : "FOREIGN KEY (vessel_id) REFERENCES api.metadata(vessel_id) ON DELETE RESTRICT"
"api.stays" {
boolean active ""
timestamp_with_time_zone arrived ""
timestamp_with_time_zone departed ""
interval duration "Best to use standard ISO 8601"
geography_Point_4326_ geog "postgis geography type default SRID 4326 Unit: degres"
integer id ""
double_precision latitude ""
double_precision longitude ""
integer moorage_id FK "Link api.moorages with api.stays via FOREIGN KEY and REFERENCES"
text name ""
text notes ""
integer stay_code FK "Link api.stays_at with api.stays via FOREIGN KEY and REFERENCES"
jsonb user_data "User-defined data Stay-specific data including images and custom fields"
text vessel_id FK "Unique identifier for the vessel associated with the api.metadata entry"
}
"api.moorages" {
text country ""
geography_Point_4326_ geog "postgis geography type default SRID 4326 Unit: degres"
boolean home_flag ""
integer id ""
double_precision latitude ""
double_precision longitude ""
text name ""
jsonb nominatim "Output of the nominatim reverse geocoding service, see https://nominatim.org/release-docs/develop/api/Reverse/"
text notes ""
jsonb overpass "Output of the overpass API, see https://wiki.openstreetmap.org/wiki/Overpass_API"
integer stay_code FK "Link api.stays_at with api.moorages via FOREIGN KEY and REFERENCES"
jsonb user_data "User-defined data Mooring-specific data including images and custom fields"
text vessel_id FK "Unique identifier for the vessel associated with the api.metadata entry"
}
"api.logbook" {
text _from "Name of the location where the log started, usually a moorage name"
double_precision _from_lat ""
double_precision _from_lng ""
integer _from_moorage_id FK "Link api.moorages with api.logbook via FOREIGN KEY and REFERENCES"
timestamp_with_time_zone _from_time ""
text _to "Name of the location where the log ended, usually a moorage name"
double_precision _to_lat ""
double_precision _to_lng ""
integer _to_moorage_id FK "Link api.moorages with api.logbook via FOREIGN KEY and REFERENCES"
timestamp_with_time_zone _to_time ""
boolean active ""
double_precision avg_speed "avg speed in knots"
numeric distance "Distance in Nautical Miles converted mobilitydb meters to NM"
interval duration "Duration in ISO 8601 format"
jsonb extra "Computed SignalK metrics such as runtime, current level, etc."
integer id ""
double_precision max_speed "max speed in knots"
double_precision max_wind_speed "true wind speed converted in knots, m/s from signalk plugin"
text name ""
text notes ""
tgeogpoint trip "MobilityDB trajectory, speed in m/s, distance in meters"
tfloat trip_awa "AWA (Apparent Wind Angle) in degrees converted from radians by signalk plugin"
tfloat trip_aws "AWS (Apparent Wind Speed), windSpeedApparent in knots converted by signalk plugin"
tfloat trip_batt_charge "Battery Charge"
tfloat trip_batt_voltage "Battery Voltage"
tfloat trip_cog "COG - Course Over Ground True in degrees converted from radians by signalk plugin"
tfloat trip_depth "Depth in meters, raw from signalk plugin"
tfloat trip_heading "Heading True in degrees converted from radians, raw from signalk plugin"
tfloat trip_hum_out "Humidity outside"
ttext trip_notes ""
tfloat trip_pres_out "Pressure outside"
tfloat trip_sog "SOG - Speed Over Ground in knots converted by signalk plugin"
tfloat trip_solar_power "solar powerPanel"
tfloat trip_solar_voltage "solar voltage"
ttext trip_status ""
tfloat trip_tank_level "Tank currentLevel"
tfloat trip_temp_out "Temperature outside in Kelvin, raw from signalk plugin"
tfloat trip_temp_water "Temperature water in Kelvin, raw from signalk plugin"
tfloat trip_twd "TWD - True Wind Direction in degrees converted from radians, raw from signalk plugin"
tfloat trip_tws "TWS - True Wind Speed in knots converted from m/s, raw from signalk plugin"
jsonb user_data "User-defined data Log-specific data including actual tags, observations, images and custom fields"
text vessel_id FK "Unique identifier for the vessel associated with the api.metadata entry"
}
"api.stays_at" {
text description ""
integer stay_code ""
}
"api.metadata" {
boolean active "trigger monitor online/offline"
jsonb available_keys "Signalk paths with unit for custom mapping"
double_precision beam ""
jsonb configuration "User-defined Signalk path mapping for metrics"
timestamp_with_time_zone created_at ""
double_precision height ""
text ip "Store vessel ip address"
double_precision length ""
text mmsi "Maritime Mobile Service Identity (MMSI) number associated with the vessel, link to public.mid"
text name ""
text platform ""
text plugin_version ""
numeric ship_type "Type of ship associated with the vessel, link to public.aistypes"
text signalk_version ""
timestamp_with_time_zone time ""
timestamp_with_time_zone updated_at ""
jsonb user_data "User-defined data including vessel polar (theoretical performance), make/model, and preferences"
text vessel_id FK "Link auth.vessels with api.metadata via FOREIGN KEY and REFERENCES"
}
"auth.vessels" {
timestamp_with_time_zone created_at ""
numeric mmsi "MMSI can be optional but if present must be a valid one and unique but must be in numeric range between 100000000 and 800000000"
text name ""
citext owner_email FK ""
name role ""
timestamp_with_time_zone updated_at ""
text vessel_id ""
}
"api.metrics" {
double_precision anglespeedapparent ""
text client_id "Deprecated client_id to be removed"
double_precision courseovergroundtrue ""
double_precision latitude "With CONSTRAINT but allow NULL value to be ignored silently by trigger"
double_precision longitude "With CONSTRAINT but allow NULL value to be ignored silently by trigger"
jsonb metrics ""
double_precision speedoverground ""
text status ""
timestamp_with_time_zone time ""
text vessel_id FK "Unique identifier for the vessel associated with the api.metadata entry"
double_precision windspeedapparent ""
}
Generated by tbls
api.stays_at
Description
Stay Type
Columns
| Name | Type | Default | Nullable | Children |
|---|---|---|---|---|
| description | text | false | ||
| stay_code | integer | false | api.moorages api.stays |
Constraints
| Name | Type | Definition |
|---|---|---|
| stays_at_description_not_null | n | NOT NULL description |
| stays_at_pkey | PRIMARY KEY | PRIMARY KEY (stay_code) |
| stays_at_stay_code_key | UNIQUE | UNIQUE (stay_code) |
| stays_at_stay_code_not_null | n | NOT NULL stay_code |
Indexes
| Name | Definition |
|---|---|
| stays_at_pkey | CREATE UNIQUE INDEX stays_at_pkey ON api.stays_at USING btree (stay_code) |
| stays_at_stay_code_key | CREATE UNIQUE INDEX stays_at_stay_code_key ON api.stays_at USING btree (stay_code) |
Relations
erDiagram
"api.moorages" }o--o| "api.stays_at" : "FOREIGN KEY (stay_code) REFERENCES api.stays_at(stay_code) ON DELETE RESTRICT"
"api.logbook" }o--o| "api.moorages" : "FOREIGN KEY (_from_moorage_id) REFERENCES api.moorages(id) ON DELETE RESTRICT"
"api.logbook" }o--o| "api.moorages" : "FOREIGN KEY (_to_moorage_id) REFERENCES api.moorages(id) ON DELETE RESTRICT"
"api.stays" }o--o| "api.moorages" : "FOREIGN KEY (moorage_id) REFERENCES api.moorages(id) ON DELETE RESTRICT"
"api.moorages" }o--|| "api.metadata" : "FOREIGN KEY (vessel_id) REFERENCES api.metadata(vessel_id) ON DELETE RESTRICT"
"api.stays" }o--o| "api.stays_at" : "FOREIGN KEY (stay_code) REFERENCES api.stays_at(stay_code) ON DELETE RESTRICT"
"api.stays" }o--|| "api.metadata" : "FOREIGN KEY (vessel_id) REFERENCES api.metadata(vessel_id) ON DELETE RESTRICT"
"api.stays_at" {
text description ""
integer stay_code ""
}
"api.moorages" {
text country ""
geography_Point_4326_ geog "postgis geography type default SRID 4326 Unit: degres"
boolean home_flag ""
integer id ""
double_precision latitude ""
double_precision longitude ""
text name ""
jsonb nominatim "Output of the nominatim reverse geocoding service, see https://nominatim.org/release-docs/develop/api/Reverse/"
text notes ""
jsonb overpass "Output of the overpass API, see https://wiki.openstreetmap.org/wiki/Overpass_API"
integer stay_code FK "Link api.stays_at with api.moorages via FOREIGN KEY and REFERENCES"
jsonb user_data "User-defined data Mooring-specific data including images and custom fields"
text vessel_id FK "Unique identifier for the vessel associated with the api.metadata entry"
}
"api.logbook" {
text _from "Name of the location where the log started, usually a moorage name"
double_precision _from_lat ""
double_precision _from_lng ""
integer _from_moorage_id FK "Link api.moorages with api.logbook via FOREIGN KEY and REFERENCES"
timestamp_with_time_zone _from_time ""
text _to "Name of the location where the log ended, usually a moorage name"
double_precision _to_lat ""
double_precision _to_lng ""
integer _to_moorage_id FK "Link api.moorages with api.logbook via FOREIGN KEY and REFERENCES"
timestamp_with_time_zone _to_time ""
boolean active ""
double_precision avg_speed "avg speed in knots"
numeric distance "Distance in Nautical Miles converted mobilitydb meters to NM"
interval duration "Duration in ISO 8601 format"
jsonb extra "Computed SignalK metrics such as runtime, current level, etc."
integer id ""
double_precision max_speed "max speed in knots"
double_precision max_wind_speed "true wind speed converted in knots, m/s from signalk plugin"
text name ""
text notes ""
tgeogpoint trip "MobilityDB trajectory, speed in m/s, distance in meters"
tfloat trip_awa "AWA (Apparent Wind Angle) in degrees converted from radians by signalk plugin"
tfloat trip_aws "AWS (Apparent Wind Speed), windSpeedApparent in knots converted by signalk plugin"
tfloat trip_batt_charge "Battery Charge"
tfloat trip_batt_voltage "Battery Voltage"
tfloat trip_cog "COG - Course Over Ground True in degrees converted from radians by signalk plugin"
tfloat trip_depth "Depth in meters, raw from signalk plugin"
tfloat trip_heading "Heading True in degrees converted from radians, raw from signalk plugin"
tfloat trip_hum_out "Humidity outside"
ttext trip_notes ""
tfloat trip_pres_out "Pressure outside"
tfloat trip_sog "SOG - Speed Over Ground in knots converted by signalk plugin"
tfloat trip_solar_power "solar powerPanel"
tfloat trip_solar_voltage "solar voltage"
ttext trip_status ""
tfloat trip_tank_level "Tank currentLevel"
tfloat trip_temp_out "Temperature outside in Kelvin, raw from signalk plugin"
tfloat trip_temp_water "Temperature water in Kelvin, raw from signalk plugin"
tfloat trip_twd "TWD - True Wind Direction in degrees converted from radians, raw from signalk plugin"
tfloat trip_tws "TWS - True Wind Speed in knots converted from m/s, raw from signalk plugin"
jsonb user_data "User-defined data Log-specific data including actual tags, observations, images and custom fields"
text vessel_id FK "Unique identifier for the vessel associated with the api.metadata entry"
}
"api.stays" {
boolean active ""
timestamp_with_time_zone arrived ""
timestamp_with_time_zone departed ""
interval duration "Best to use standard ISO 8601"
geography_Point_4326_ geog "postgis geography type default SRID 4326 Unit: degres"
integer id ""
double_precision latitude ""
double_precision longitude ""
integer moorage_id FK "Link api.moorages with api.stays via FOREIGN KEY and REFERENCES"
text name ""
text notes ""
integer stay_code FK "Link api.stays_at with api.stays via FOREIGN KEY and REFERENCES"
jsonb user_data "User-defined data Stay-specific data including images and custom fields"
text vessel_id FK "Unique identifier for the vessel associated with the api.metadata entry"
}
"api.metadata" {
boolean active "trigger monitor online/offline"
jsonb available_keys "Signalk paths with unit for custom mapping"
double_precision beam ""
jsonb configuration "User-defined Signalk path mapping for metrics"
timestamp_with_time_zone created_at ""
double_precision height ""
text ip "Store vessel ip address"
double_precision length ""
text mmsi "Maritime Mobile Service Identity (MMSI) number associated with the vessel, link to public.mid"
text name ""
text platform ""
text plugin_version ""
numeric ship_type "Type of ship associated with the vessel, link to public.aistypes"
text signalk_version ""
timestamp_with_time_zone time ""
timestamp_with_time_zone updated_at ""
jsonb user_data "User-defined data including vessel polar (theoretical performance), make/model, and preferences"
text vessel_id FK "Link auth.vessels with api.metadata via FOREIGN KEY and REFERENCES"
}
Generated by tbls
api.stays_geojson_view
Description
List stays as geojson
Table Definition
CREATE VIEW stays_geojson_view AS (
SELECT (st_asgeojson(tbl.*))::jsonb AS geojson
FROM ( SELECT stay_explore_view.stay_id,
stay_explore_view.moorage_id,
stay_explore_view.moorage_name,
stay_explore_view.stay_name,
stay_explore_view.arrived,
stay_explore_view.stay_code,
stay_explore_view.latitude,
stay_explore_view.longitude,
stay_explore_view.stay_notes,
stay_explore_view.moorage_notes,
stay_explore_view.has_images,
stay_explore_view.images,
st_makepoint(stay_explore_view.longitude, stay_explore_view.latitude) AS st_makepoint
FROM api.stay_explore_view) tbl
)
Columns
| Name | Type | Default | Nullable |
|---|---|---|---|
| geojson | jsonb | true |
Referenced Tables
| Name | Columns | Comment | Type |
|---|---|---|---|
| api.stay_explore_view | 14 | List moorages notes order by stays | VIEW |
Relations
erDiagram
"api.stays_geojson_view" {
jsonb geojson ""
}
Generated by tbls
api.stays_view
Description
Stays web view
Table Definition
CREATE VIEW stays_view AS (
SELECT s.id,
s.name,
m.name AS moorage,
m.id AS moorage_id,
(s.departed - s.arrived) AS duration,
sa.description AS stayed_at,
sa.stay_code AS stayed_at_id,
s.arrived,
_from.id AS arrived_log_id,
_from._to_moorage_id AS arrived_from_moorage_id,
_from._to AS arrived_from_moorage_name,
s.departed,
_to.id AS departed_log_id,
_to._from_moorage_id AS departed_to_moorage_id,
_to._from AS departed_to_moorage_name,
s.notes
FROM api.stays_at sa,
api.moorages m,
((api.stays s
LEFT JOIN api.logbook _from ON ((_from._from_time = s.departed)))
LEFT JOIN api.logbook _to ON ((_to._to_time = s.arrived)))
WHERE ((s.departed IS NOT NULL) AND (_from._to_moorage_id IS NOT NULL) AND (s.name IS NOT NULL) AND (s.stay_code = sa.stay_code) AND (s.moorage_id = m.id))
ORDER BY s.arrived DESC
)
Columns
| Name | Type | Default | Nullable |
|---|---|---|---|
| arrived | timestamp with time zone | true | |
| arrived_from_moorage_id | integer | true | |
| arrived_from_moorage_name | text | true | |
| arrived_log_id | integer | true | |
| departed | timestamp with time zone | true | |
| departed_log_id | integer | true | |
| departed_to_moorage_id | integer | true | |
| departed_to_moorage_name | text | true | |
| duration | interval | true | |
| id | integer | true | |
| moorage | text | true | |
| moorage_id | integer | true | |
| name | text | true | |
| notes | text | true | |
| stayed_at | text | true | |
| stayed_at_id | integer | true |
Referenced Tables
| Name | Columns | Comment | Type |
|---|---|---|---|
| api.stays_at | 2 | Stay Type | BASE TABLE |
| api.logbook | 42 | Stores generated logbook | BASE TABLE |
Relations
erDiagram
"api.stays_view" {
timestamp_with_time_zone arrived ""
integer arrived_from_moorage_id ""
text arrived_from_moorage_name ""
integer arrived_log_id ""
timestamp_with_time_zone departed ""
integer departed_log_id ""
integer departed_to_moorage_id ""
text departed_to_moorage_name ""
interval duration ""
integer id ""
text moorage ""
integer moorage_id ""
text name ""
text notes ""
text stayed_at ""
integer stayed_at_id ""
}
Generated by tbls
api.total_info_view
Description
total_info_view web view
Table Definition
CREATE VIEW total_info_view AS (
WITH l AS (
SELECT count(*) AS logs
FROM api.logbook
), s AS (
SELECT count(*) AS stays
FROM api.stays
), m AS (
SELECT count(*) AS moorages
FROM api.moorages
)
SELECT l.logs,
s.stays,
m.moorages
FROM l,
s,
m
)
Columns
| Name | Type | Default | Nullable |
|---|---|---|---|
| logs | bigint | true | |
| moorages | bigint | true | |
| stays | bigint | true |
Referenced Tables
| Name | Columns | Comment | Type |
|---|---|---|---|
| api.logbook | 42 | Stores generated logbook | BASE TABLE |
| api.stays | 14 | Stores generated stays | BASE TABLE |
| api.moorages | 13 | Stores generated moorages | BASE TABLE |
Relations
erDiagram
"api.total_info_view" {
bigint logs ""
bigint moorages ""
bigint stays ""
}
Generated by tbls
api.versions_view
Description
Expose as a table view app and system version to API
Table Definition
CREATE VIEW versions_view AS (
SELECT value AS api_version,
rtrim("substring"(version(), 0, 17)) AS sys_version,
( SELECT pg_extension.extversion AS timescaledb
FROM pg_extension
WHERE (pg_extension.extname = 'timescaledb'::name)) AS timescaledb,
( SELECT pg_extension.extversion AS postgis
FROM pg_extension
WHERE (pg_extension.extname = 'postgis'::name)) AS postgis,
( SELECT rtrim("substring"(pg_stat_activity.application_name, 'PostgREST [0-9.]+'::text)) AS postgrest
FROM pg_stat_activity
WHERE (pg_stat_activity.application_name ~~* '%postgrest%'::text)
LIMIT 1) AS postgrest
FROM app_settings
WHERE (name = 'app.version'::text)
)
Columns
| Name | Type | Default | Nullable |
|---|---|---|---|
| api_version | text | true | |
| postgis | text | true | |
| postgrest | text | true | |
| sys_version | text | true | |
| timescaledb | text | true |
Referenced Tables
| Name | Columns | Comment | Type |
|---|---|---|---|
| pg_extension | 0 | ||
| pg_stat_activity | 0 | ||
| public.app_settings | 2 | application settings | BASE TABLE |
Relations
erDiagram
"api.versions_view" {
text api_version ""
text postgis ""
text postgrest ""
text sys_version ""
text timescaledb ""
}
Generated by tbls
api.vessels_view
Description
Expose vessels listing to web api
Table Definition
CREATE VIEW vessels_view AS (
WITH metrics AS (
SELECT COALESCE((( SELECT m."time"
FROM api.metrics m
WHERE (m.vessel_id = current_setting('vessel.id'::text))
ORDER BY m."time" DESC
LIMIT 1))::text, NULL::text) AS last_metrics
), metadata AS (
SELECT COALESCE((( SELECT m."time"
FROM api.metadata m
WHERE (m.vessel_id = current_setting('vessel.id'::text))))::text, NULL::text) AS last_contact
)
SELECT v.name,
v.mmsi,
v.created_at,
metadata.last_contact,
((((now() AT TIME ZONE 'UTC'::text))::timestamp with time zone - (metadata.last_contact)::timestamp with time zone) > 'PT1H10M'::interval) AS offline,
(((now() AT TIME ZONE 'UTC'::text))::timestamp with time zone - (metadata.last_contact)::timestamp with time zone) AS duration,
metrics.last_metrics,
((((now() AT TIME ZONE 'UTC'::text))::timestamp with time zone - (metrics.last_metrics)::timestamp with time zone) > 'PT1H10M'::interval) AS metrics_offline,
(((now() AT TIME ZONE 'UTC'::text))::timestamp with time zone - (metrics.last_metrics)::timestamp with time zone) AS duration_last_metrics
FROM auth.vessels v,
metadata,
metrics
WHERE ((v.owner_email)::text = current_setting('user.email'::text))
)
Columns
| Name | Type | Default | Nullable |
|---|---|---|---|
| created_at | timestamp with time zone | true | |
| duration | interval | true | |
| duration_last_metrics | interval | true | |
| last_contact | text | true | |
| last_metrics | text | true | |
| metrics_offline | boolean | true | |
| mmsi | numeric | true | |
| name | text | true | |
| offline | boolean | true |
Referenced Tables
| Name | Columns | Comment | Type |
|---|---|---|---|
| api.metrics | 11 | Stores metrics from vessel | BASE TABLE |
| api.metadata | 18 | Stores metadata received from vessel, aka signalk plugin | BASE TABLE |
| auth.vessels | 7 | vessels table link to accounts email user_id column | BASE TABLE |
Relations
erDiagram
"api.vessels_view" {
timestamp_with_time_zone created_at ""
interval duration ""
interval duration_last_metrics ""
text last_contact ""
text last_metrics ""
boolean metrics_offline ""
numeric mmsi ""
text name ""
boolean offline ""
}
Generated by tbls
auth.accounts
Description
users account table
Columns
| Name | Type | Default | Nullable | Children | Comment |
|---|---|---|---|---|---|
| connected_at | timestamp with time zone | now() | false | ||
| created_at | timestamp with time zone | now() | false | ||
| citext | false | auth.otp auth.vessels | |||
| first | text | false | User first name with CONSTRAINT CHECK | ||
| id | integer | false | |||
| last | text | false | User last name with CONSTRAINT CHECK | ||
| pass | text | false | |||
| preferences | jsonb | ‘{“email_notifications”: true}’::jsonb | true | ||
| role | name | false | |||
| updated_at | timestamp with time zone | now() | false | ||
| user_id | text | “right”((gen_random_uuid())::text, 12) | false |
Constraints
| Name | Type | Definition |
|---|---|---|
| accounts_connected_at_not_null | n | NOT NULL connected_at |
| accounts_created_at_not_null | n | NOT NULL created_at |
| accounts_email_check | CHECK | CHECK ((email ~* ‘^.+@.+..+$’::citext)) |
| accounts_email_not_null | n | NOT NULL email |
| accounts_first_not_null | n | NOT NULL first |
| accounts_id_key | UNIQUE | UNIQUE (id) |
| accounts_id_not_null | n | NOT NULL id |
| accounts_last_not_null | n | NOT NULL last |
| accounts_pass_not_null | n | NOT NULL pass |
| accounts_pkey | PRIMARY KEY | PRIMARY KEY (email) |
| accounts_role_not_null | n | NOT NULL role |
| accounts_updated_at_not_null | n | NOT NULL updated_at |
| accounts_user_id_key | UNIQUE | UNIQUE (user_id) |
| accounts_user_id_not_null | n | NOT NULL user_id |
| ensure_user_role_exists | TRIGGER | CREATE CONSTRAINT TRIGGER ensure_user_role_exists AFTER INSERT OR UPDATE ON auth.accounts NOT DEFERRABLE INITIALLY IMMEDIATE FOR EACH ROW EXECUTE FUNCTION auth.check_role_exists() |
| valid_email | CHECK | CHECK ((length((email)::text) > 5)) |
| valid_first | CHECK | CHECK (((length(first) > 1) AND (length(first) < 512))) |
| valid_last | CHECK | CHECK (((length(last) > 1) AND (length(last) < 512))) |
| valid_pass | CHECK | CHECK (((length(pass) > 4) AND (length(pass) < 512))) |
Indexes
| Name | Definition |
|---|---|
| accounts_id_key | CREATE UNIQUE INDEX accounts_id_key ON auth.accounts USING btree (id) |
| accounts_pkey | CREATE UNIQUE INDEX accounts_pkey ON auth.accounts USING btree (email) |
| accounts_preferences_idx | CREATE INDEX accounts_preferences_idx ON auth.accounts USING gin (preferences) |
| accounts_user_id_key | CREATE UNIQUE INDEX accounts_user_id_key ON auth.accounts USING btree (user_id) |
Triggers
| Name | Definition | Comment |
|---|---|---|
| accounts_moddatetime | CREATE TRIGGER accounts_moddatetime BEFORE UPDATE ON auth.accounts FOR EACH ROW EXECUTE FUNCTION moddatetime(‘updated_at’) | Automatic update of updated_at on table modification |
| encrypt_pass | CREATE TRIGGER encrypt_pass BEFORE INSERT OR UPDATE ON auth.accounts FOR EACH ROW EXECUTE FUNCTION auth.encrypt_pass() | execute function auth.encrypt_pass() |
| ensure_user_role_exists | CREATE CONSTRAINT TRIGGER ensure_user_role_exists AFTER INSERT OR UPDATE ON auth.accounts NOT DEFERRABLE INITIALLY IMMEDIATE FOR EACH ROW EXECUTE FUNCTION auth.check_role_exists() | ensure user role exists |
| new_account_entry | CREATE TRIGGER new_account_entry AFTER INSERT ON auth.accounts FOR EACH ROW EXECUTE FUNCTION new_account_entry_fn() | Add new account in process_queue for further processing |
Relations
erDiagram
"auth.otp" |o--|| "auth.accounts" : "FOREIGN KEY (user_email) REFERENCES auth.accounts(email) ON DELETE RESTRICT"
"auth.vessels" }o--|| "auth.accounts" : "FOREIGN KEY (owner_email) REFERENCES auth.accounts(email) ON DELETE RESTRICT"
"api.metadata" |o--|| "auth.vessels" : "FOREIGN KEY (vessel_id) REFERENCES auth.vessels(vessel_id) ON DELETE RESTRICT"
"auth.accounts" {
timestamp_with_time_zone connected_at ""
timestamp_with_time_zone created_at ""
citext email ""
text first "User first name with CONSTRAINT CHECK"
integer id ""
text last "User last name with CONSTRAINT CHECK"
text pass ""
jsonb preferences ""
name role ""
timestamp_with_time_zone updated_at ""
text user_id ""
}
"auth.otp" {
text otp_pass ""
timestamp_with_time_zone otp_timestamp ""
smallint otp_tries ""
citext user_email FK ""
}
"auth.vessels" {
timestamp_with_time_zone created_at ""
numeric mmsi "MMSI can be optional but if present must be a valid one and unique but must be in numeric range between 100000000 and 800000000"
text name ""
citext owner_email FK ""
name role ""
timestamp_with_time_zone updated_at ""
text vessel_id ""
}
"api.metadata" {
boolean active "trigger monitor online/offline"
jsonb available_keys "Signalk paths with unit for custom mapping"
double_precision beam ""
jsonb configuration "User-defined Signalk path mapping for metrics"
timestamp_with_time_zone created_at ""
double_precision height ""
text ip "Store vessel ip address"
double_precision length ""
text mmsi "Maritime Mobile Service Identity (MMSI) number associated with the vessel, link to public.mid"
text name ""
text platform ""
text plugin_version ""
numeric ship_type "Type of ship associated with the vessel, link to public.aistypes"
text signalk_version ""
timestamp_with_time_zone time ""
timestamp_with_time_zone updated_at ""
jsonb user_data "User-defined data including vessel polar (theoretical performance), make/model, and preferences"
text vessel_id FK "Link auth.vessels with api.metadata via FOREIGN KEY and REFERENCES"
}
Generated by tbls
auth.otp
Description
Stores temporal otp code for up to 15 minutes
Columns
| Name | Type | Default | Nullable | Parents |
|---|---|---|---|---|
| otp_pass | text | false | ||
| otp_timestamp | timestamp with time zone | now() | true | |
| otp_tries | smallint | ‘0’::smallint | false | |
| user_email | citext | false | auth.accounts |
Constraints
| Name | Type | Definition |
|---|---|---|
| otp_otp_pass_not_null | n | NOT NULL otp_pass |
| otp_otp_tries_not_null | n | NOT NULL otp_tries |
| otp_pkey | PRIMARY KEY | PRIMARY KEY (user_email) |
| otp_user_email_fkey | FOREIGN KEY | FOREIGN KEY (user_email) REFERENCES auth.accounts(email) ON DELETE RESTRICT |
| otp_user_email_not_null | n | NOT NULL user_email |
Indexes
| Name | Definition |
|---|---|
| otp_pass_idx | CREATE INDEX otp_pass_idx ON auth.otp USING btree (otp_pass) |
| otp_pkey | CREATE UNIQUE INDEX otp_pkey ON auth.otp USING btree (user_email) |
Relations
erDiagram
"auth.otp" |o--|| "auth.accounts" : "FOREIGN KEY (user_email) REFERENCES auth.accounts(email) ON DELETE RESTRICT"
"auth.vessels" }o--|| "auth.accounts" : "FOREIGN KEY (owner_email) REFERENCES auth.accounts(email) ON DELETE RESTRICT"
"auth.otp" {
text otp_pass ""
timestamp_with_time_zone otp_timestamp ""
smallint otp_tries ""
citext user_email FK ""
}
"auth.accounts" {
timestamp_with_time_zone connected_at ""
timestamp_with_time_zone created_at ""
citext email ""
text first "User first name with CONSTRAINT CHECK"
integer id ""
text last "User last name with CONSTRAINT CHECK"
text pass ""
jsonb preferences ""
name role ""
timestamp_with_time_zone updated_at ""
text user_id ""
}
"auth.vessels" {
timestamp_with_time_zone created_at ""
numeric mmsi "MMSI can be optional but if present must be a valid one and unique but must be in numeric range between 100000000 and 800000000"
text name ""
citext owner_email FK ""
name role ""
timestamp_with_time_zone updated_at ""
text vessel_id ""
}
Generated by tbls
auth.vessels
Description
vessels table link to accounts email user_id column
Columns
| Name | Type | Default | Nullable | Children | Parents | Comment |
|---|---|---|---|---|---|---|
| created_at | timestamp with time zone | now() | false | |||
| mmsi | numeric | true | MMSI can be optional but if present must be a valid one and unique but must be in numeric range between 100000000 and 800000000 | |||
| name | text | false | ||||
| owner_email | citext | false | auth.accounts | |||
| role | name | false | ||||
| updated_at | timestamp with time zone | now() | false | |||
| vessel_id | text | “right”((gen_random_uuid())::text, 12) | false | api.metadata |
Constraints
| Name | Type | Definition |
|---|---|---|
| ensure_vessel_role_exists | TRIGGER | CREATE CONSTRAINT TRIGGER ensure_vessel_role_exists AFTER INSERT OR UPDATE ON auth.vessels NOT DEFERRABLE INITIALLY IMMEDIATE FOR EACH ROW EXECUTE FUNCTION auth.check_role_exists() |
| valid_range_mmsi | CHECK | CHECK (((mmsi > (100000000)::numeric) AND (mmsi < (800000000)::numeric))) |
| vessels_created_at_not_null | n | NOT NULL created_at |
| vessels_mmsi_key | UNIQUE | UNIQUE (mmsi) |
| vessels_name_check | CHECK | CHECK (((length(name) >= 3) AND (length(name) < 512))) |
| vessels_name_not_null | n | NOT NULL name |
| vessels_owner_email_fkey | FOREIGN KEY | FOREIGN KEY (owner_email) REFERENCES auth.accounts(email) ON DELETE RESTRICT |
| vessels_owner_email_not_null | n | NOT NULL owner_email |
| vessels_pkey | PRIMARY KEY | PRIMARY KEY (vessel_id) |
| vessels_role_check | CHECK | CHECK ((length((role)::text) < 512)) |
| vessels_role_not_null | n | NOT NULL role |
| vessels_updated_at_not_null | n | NOT NULL updated_at |
| vessels_vessel_id_key | UNIQUE | UNIQUE (vessel_id) |
| vessels_vessel_id_not_null | n | NOT NULL vessel_id |
Indexes
| Name | Definition |
|---|---|
| vessels_mmsi_key | CREATE UNIQUE INDEX vessels_mmsi_key ON auth.vessels USING btree (mmsi) |
| vessels_owner_email_idx | CREATE INDEX vessels_owner_email_idx ON auth.vessels USING btree (owner_email) |
| vessels_pkey | CREATE UNIQUE INDEX vessels_pkey ON auth.vessels USING btree (vessel_id) |
| vessels_vessel_id_key | CREATE UNIQUE INDEX vessels_vessel_id_key ON auth.vessels USING btree (vessel_id) |
Triggers
| Name | Definition | Comment |
|---|---|---|
| ensure_vessel_role_exists | CREATE CONSTRAINT TRIGGER ensure_vessel_role_exists AFTER INSERT OR UPDATE ON auth.vessels NOT DEFERRABLE INITIALLY IMMEDIATE FOR EACH ROW EXECUTE FUNCTION auth.check_role_exists() | ensure vessel role exists |
| new_vessel_entry | CREATE TRIGGER new_vessel_entry AFTER INSERT ON auth.vessels FOR EACH ROW EXECUTE FUNCTION new_vessel_entry_fn() | Add new vessel in process_queue for further processing |
| new_vessel_public | CREATE TRIGGER new_vessel_public AFTER INSERT ON auth.vessels FOR EACH ROW EXECUTE FUNCTION new_vessel_public_fn() | Add new vessel name as public_vessel user configuration |
| new_vessel_trim | CREATE TRIGGER new_vessel_trim BEFORE INSERT ON auth.vessels FOR EACH ROW EXECUTE FUNCTION new_vessel_trim_fn() | Trim space vessel name |
| vessels_moddatetime | CREATE TRIGGER vessels_moddatetime BEFORE UPDATE ON auth.vessels FOR EACH ROW EXECUTE FUNCTION moddatetime(‘updated_at’) | Automatic update of updated_at on table modification |
Relations
erDiagram
"auth.vessels" }o--|| "auth.accounts" : "FOREIGN KEY (owner_email) REFERENCES auth.accounts(email) ON DELETE RESTRICT"
"auth.otp" |o--|| "auth.accounts" : "FOREIGN KEY (user_email) REFERENCES auth.accounts(email) ON DELETE RESTRICT"
"api.metadata" |o--|| "auth.vessels" : "FOREIGN KEY (vessel_id) REFERENCES auth.vessels(vessel_id) ON DELETE RESTRICT"
"api.logbook" }o--|| "api.metadata" : "FOREIGN KEY (vessel_id) REFERENCES api.metadata(vessel_id) ON DELETE RESTRICT"
"api.metrics" }o--|| "api.metadata" : "FOREIGN KEY (vessel_id) REFERENCES api.metadata(vessel_id) ON DELETE RESTRICT"
"api.moorages" }o--|| "api.metadata" : "FOREIGN KEY (vessel_id) REFERENCES api.metadata(vessel_id) ON DELETE RESTRICT"
"api.stays" }o--|| "api.metadata" : "FOREIGN KEY (vessel_id) REFERENCES api.metadata(vessel_id) ON DELETE RESTRICT"
"auth.vessels" {
timestamp_with_time_zone created_at ""
numeric mmsi "MMSI can be optional but if present must be a valid one and unique but must be in numeric range between 100000000 and 800000000"
text name ""
citext owner_email FK ""
name role ""
timestamp_with_time_zone updated_at ""
text vessel_id ""
}
"auth.accounts" {
timestamp_with_time_zone connected_at ""
timestamp_with_time_zone created_at ""
citext email ""
text first "User first name with CONSTRAINT CHECK"
integer id ""
text last "User last name with CONSTRAINT CHECK"
text pass ""
jsonb preferences ""
name role ""
timestamp_with_time_zone updated_at ""
text user_id ""
}
"auth.otp" {
text otp_pass ""
timestamp_with_time_zone otp_timestamp ""
smallint otp_tries ""
citext user_email FK ""
}
"api.metadata" {
boolean active "trigger monitor online/offline"
jsonb available_keys "Signalk paths with unit for custom mapping"
double_precision beam ""
jsonb configuration "User-defined Signalk path mapping for metrics"
timestamp_with_time_zone created_at ""
double_precision height ""
text ip "Store vessel ip address"
double_precision length ""
text mmsi "Maritime Mobile Service Identity (MMSI) number associated with the vessel, link to public.mid"
text name ""
text platform ""
text plugin_version ""
numeric ship_type "Type of ship associated with the vessel, link to public.aistypes"
text signalk_version ""
timestamp_with_time_zone time ""
timestamp_with_time_zone updated_at ""
jsonb user_data "User-defined data including vessel polar (theoretical performance), make/model, and preferences"
text vessel_id FK "Link auth.vessels with api.metadata via FOREIGN KEY and REFERENCES"
}
"api.logbook" {
text _from "Name of the location where the log started, usually a moorage name"
double_precision _from_lat ""
double_precision _from_lng ""
integer _from_moorage_id FK "Link api.moorages with api.logbook via FOREIGN KEY and REFERENCES"
timestamp_with_time_zone _from_time ""
text _to "Name of the location where the log ended, usually a moorage name"
double_precision _to_lat ""
double_precision _to_lng ""
integer _to_moorage_id FK "Link api.moorages with api.logbook via FOREIGN KEY and REFERENCES"
timestamp_with_time_zone _to_time ""
boolean active ""
double_precision avg_speed "avg speed in knots"
numeric distance "Distance in Nautical Miles converted mobilitydb meters to NM"
interval duration "Duration in ISO 8601 format"
jsonb extra "Computed SignalK metrics such as runtime, current level, etc."
integer id ""
double_precision max_speed "max speed in knots"
double_precision max_wind_speed "true wind speed converted in knots, m/s from signalk plugin"
text name ""
text notes ""
tgeogpoint trip "MobilityDB trajectory, speed in m/s, distance in meters"
tfloat trip_awa "AWA (Apparent Wind Angle) in degrees converted from radians by signalk plugin"
tfloat trip_aws "AWS (Apparent Wind Speed), windSpeedApparent in knots converted by signalk plugin"
tfloat trip_batt_charge "Battery Charge"
tfloat trip_batt_voltage "Battery Voltage"
tfloat trip_cog "COG - Course Over Ground True in degrees converted from radians by signalk plugin"
tfloat trip_depth "Depth in meters, raw from signalk plugin"
tfloat trip_heading "Heading True in degrees converted from radians, raw from signalk plugin"
tfloat trip_hum_out "Humidity outside"
ttext trip_notes ""
tfloat trip_pres_out "Pressure outside"
tfloat trip_sog "SOG - Speed Over Ground in knots converted by signalk plugin"
tfloat trip_solar_power "solar powerPanel"
tfloat trip_solar_voltage "solar voltage"
ttext trip_status ""
tfloat trip_tank_level "Tank currentLevel"
tfloat trip_temp_out "Temperature outside in Kelvin, raw from signalk plugin"
tfloat trip_temp_water "Temperature water in Kelvin, raw from signalk plugin"
tfloat trip_twd "TWD - True Wind Direction in degrees converted from radians, raw from signalk plugin"
tfloat trip_tws "TWS - True Wind Speed in knots converted from m/s, raw from signalk plugin"
jsonb user_data "User-defined data Log-specific data including actual tags, observations, images and custom fields"
text vessel_id FK "Unique identifier for the vessel associated with the api.metadata entry"
}
"api.metrics" {
double_precision anglespeedapparent ""
text client_id "Deprecated client_id to be removed"
double_precision courseovergroundtrue ""
double_precision latitude "With CONSTRAINT but allow NULL value to be ignored silently by trigger"
double_precision longitude "With CONSTRAINT but allow NULL value to be ignored silently by trigger"
jsonb metrics ""
double_precision speedoverground ""
text status ""
timestamp_with_time_zone time ""
text vessel_id FK "Unique identifier for the vessel associated with the api.metadata entry"
double_precision windspeedapparent ""
}
"api.moorages" {
text country ""
geography_Point_4326_ geog "postgis geography type default SRID 4326 Unit: degres"
boolean home_flag ""
integer id ""
double_precision latitude ""
double_precision longitude ""
text name ""
jsonb nominatim "Output of the nominatim reverse geocoding service, see https://nominatim.org/release-docs/develop/api/Reverse/"
text notes ""
jsonb overpass "Output of the overpass API, see https://wiki.openstreetmap.org/wiki/Overpass_API"
integer stay_code FK "Link api.stays_at with api.moorages via FOREIGN KEY and REFERENCES"
jsonb user_data "User-defined data Mooring-specific data including images and custom fields"
text vessel_id FK "Unique identifier for the vessel associated with the api.metadata entry"
}
"api.stays" {
boolean active ""
timestamp_with_time_zone arrived ""
timestamp_with_time_zone departed ""
interval duration "Best to use standard ISO 8601"
geography_Point_4326_ geog "postgis geography type default SRID 4326 Unit: degres"
integer id ""
double_precision latitude ""
double_precision longitude ""
integer moorage_id FK "Link api.moorages with api.stays via FOREIGN KEY and REFERENCES"
text name ""
text notes ""
integer stay_code FK "Link api.stays_at with api.stays via FOREIGN KEY and REFERENCES"
jsonb user_data "User-defined data Stay-specific data including images and custom fields"
text vessel_id FK "Unique identifier for the vessel associated with the api.metadata entry"
}
Generated by tbls
public.aistypes
Description
aistypes AIS Ship Types, https://api.vesselfinder.com/docs/ref-aistypes.html
Columns
| Name | Type | Default | Nullable |
|---|---|---|---|
| description | text | true | |
| id | numeric | true |
Constraints
| Name | Type | Definition |
|---|---|---|
| aistypes_id_key | UNIQUE | UNIQUE (id) |
Indexes
| Name | Definition |
|---|---|
| aistypes_id_key | CREATE UNIQUE INDEX aistypes_id_key ON public.aistypes USING btree (id) |
Relations
erDiagram
"public.aistypes" {
text description ""
numeric id ""
}
Generated by tbls
public.app_settings
Description
application settings
Columns
| Name | Type | Default | Nullable | Comment |
|---|---|---|---|---|
| name | text | false | application settings name key | |
| value | text | false | application settings value |
Constraints
| Name | Type | Definition |
|---|---|---|
| app_settings_name_key | UNIQUE | UNIQUE (name) |
| app_settings_name_not_null | n | NOT NULL name |
| app_settings_value_not_null | n | NOT NULL value |
Indexes
| Name | Definition |
|---|---|
| app_settings_name_key | CREATE UNIQUE INDEX app_settings_name_key ON public.app_settings USING btree (name) |
Relations
erDiagram
"public.app_settings" {
text name "application settings name key"
text value "application settings value"
}
Generated by tbls
public.badges
Description
Badges descriptions
Columns
| Name | Type | Default | Nullable |
|---|---|---|---|
| description | text | true | |
| name | text | true |
Constraints
| Name | Type | Definition |
|---|---|---|
| badges_name_key | UNIQUE | UNIQUE (name) |
Indexes
| Name | Definition |
|---|---|
| badges_name_key | CREATE UNIQUE INDEX badges_name_key ON public.badges USING btree (name) |
Relations
erDiagram
"public.badges" {
text description ""
text name ""
}
Generated by tbls
public.email_templates
Description
email/message templates for notifications
Columns
| Name | Type | Default | Nullable |
|---|---|---|---|
| email_content | text | true | |
| email_subject | text | true | |
| name | text | true | |
| pushover_message | text | true | |
| pushover_title | text | true |
Constraints
| Name | Type | Definition |
|---|---|---|
| email_templates_name_key | UNIQUE | UNIQUE (name) |
Indexes
| Name | Definition |
|---|---|
| email_templates_name_key | CREATE UNIQUE INDEX email_templates_name_key ON public.email_templates USING btree (name) |
Relations
erDiagram
"public.email_templates" {
text email_content ""
text email_subject ""
text name ""
text pushover_message ""
text pushover_title ""
}
Generated by tbls
public.geocoders
Description
geo service nominatim url
Columns
| Name | Type | Default | Nullable |
|---|---|---|---|
| name | text | true | |
| reverse_url | text | true | |
| url | text | true |
Constraints
| Name | Type | Definition |
|---|---|---|
| geocoders_name_key | UNIQUE | UNIQUE (name) |
Indexes
| Name | Definition |
|---|---|
| geocoders_name_key | CREATE UNIQUE INDEX geocoders_name_key ON public.geocoders USING btree (name) |
Relations
erDiagram
"public.geocoders" {
text name ""
text reverse_url ""
text url ""
}
Generated by tbls
public.iso3166
Description
This is a complete list of all country ISO codes as described in the ISO 3166 international standard. Country Codes Alpha-2 & Alpha-3 https://www.iban.com/country-codes
Columns
| Name | Type | Default | Nullable |
|---|---|---|---|
| alpha_2 | text | true | |
| alpha_3 | text | true | |
| country | text | true | |
| id | integer | true |
Relations
erDiagram
"public.iso3166" {
text alpha_2 ""
text alpha_3 ""
text country ""
integer id ""
}
Generated by tbls
public.mid
Description
MMSI MID Codes (Maritime Mobile Service Identity) Filtered by Flag of Registration, https://www.marinevesseltraffic.com/2013/11/mmsi-mid-codes-by-flag.html
Columns
| Name | Type | Default | Nullable |
|---|---|---|---|
| country | text | true | |
| country_id | integer | true | |
| id | numeric | true |
Constraints
| Name | Type | Definition |
|---|---|---|
| mid_id_key | UNIQUE | UNIQUE (id) |
Indexes
| Name | Definition |
|---|---|
| mid_id_key | CREATE UNIQUE INDEX mid_id_key ON public.mid USING btree (id) |
Relations
erDiagram
"public.mid" {
text country ""
integer country_id ""
numeric id ""
}
Generated by tbls
public.process_queue
Description
process queue for async job
Columns
| Name | Type | Default | Nullable | Comment |
|---|---|---|---|---|
| channel | text | false | ||
| id | integer | false | ||
| payload | text | false | ||
| processed | timestamp with time zone | true | ||
| ref_id | text | false | either user_id or vessel_id | |
| stored | timestamp with time zone | false |
Constraints
| Name | Type | Definition |
|---|---|---|
| process_queue_channel_not_null | n | NOT NULL channel |
| process_queue_id_not_null | n | NOT NULL id |
| process_queue_payload_not_null | n | NOT NULL payload |
| process_queue_pkey | PRIMARY KEY | PRIMARY KEY (id) |
| process_queue_ref_id_not_null | n | NOT NULL ref_id |
| process_queue_stored_not_null | n | NOT NULL stored |
Indexes
| Name | Definition |
|---|---|
| process_queue_channel_idx | CREATE INDEX process_queue_channel_idx ON public.process_queue USING btree (channel) |
| process_queue_new_logbook_priority_idx | CREATE INDEX process_queue_new_logbook_priority_idx ON public.process_queue USING btree (channel, processed, stored) WHERE (processed IS NULL) |
| process_queue_pending_idx | CREATE INDEX process_queue_pending_idx ON public.process_queue USING btree (channel, stored DESC) WHERE (processed IS NULL) |
| process_queue_pkey | CREATE UNIQUE INDEX process_queue_pkey ON public.process_queue USING btree (id) |
| process_queue_processed_idx | CREATE INDEX process_queue_processed_idx ON public.process_queue USING btree (processed) |
| process_queue_ref_id_idx | CREATE INDEX process_queue_ref_id_idx ON public.process_queue USING btree (ref_id) |
| process_queue_stored_idx | CREATE INDEX process_queue_stored_idx ON public.process_queue USING btree (stored) |
Relations
erDiagram
"public.process_queue" {
text channel ""
integer id ""
text payload ""
timestamp_with_time_zone processed ""
text ref_id "either user_id or vessel_id"
timestamp_with_time_zone stored ""
}
Generated by tbls
Development
docker
Install docker and docker-compose
A full-featured development environment.
With CodeSandbox
- Develop on
- or via direct link
With DevPod
- or via direct link
With Docker Dev Environments
Git setup
The recommended setup for both core and casual contributors is to always create a fork
of the primary repo under their own account. The local repo should have two remotes: upstream pointing to the primary xbgmsharp/postgsail repo, and origin pointing to the user’s own fork. The main branch should track upstream/main, but all new work will be pushed to origin and PRs will be created from there.
Rationale for this setup (click to expand)
This rationale was copied from a post by Yuri
Open source contribution is both a technical and a social phenomenon. Any FOSS project naturally has a “caste system” - a group of contributors with extensive rights vs everyone else. Some of this separation is necessary - core contributors have deeper knowledge of the code, share vision, and trust each other.
Core contributors have one more right that others do not – they can create repository branches. Thus, they can contribute “locally” - by pushing proposed changes to the primary repository’s work branches, and create “local” pull requests inside the same repo. This is different from others, who can contribute only from their own forks.
There is little difference between creating pull requests from one’s own fork and from the primary repo, and there are a few reasons why core contributors should never do it from the primary repo:
- it ensures that casual contributors always run the same CI as core contributors. If contribution process breaks, it will affect everyone, and will get fixed faster.
- it puts everyone on the same leveled playing field, reducing the “caste system” effect, making the project feel more welcoming to new contributors
- it ensures that the primary repo only has maintained branches (e.g.
mainandv1.x), not a bunch of PR branches whose ownership and work status is unclear to everyone
In the martin repository, we follow this and have a branch protection rule that prevents core contributors from creating pull requests from the primary repo.
# clone the primary fork to your local machine, naming the remote "upstream"
# make sure to replace the URL with the correct one
git clone -o upstream https://github.com/xbgmsharp/postgsail.git
cd martin
# add your own fork as a remote, naming it "origin"
git remote add origin https://github.com/username/postgsail.git
For further setup instructions for IDEs, please see the Getting Involved step after you have installed the necessary tools below.
If you have already cloned the repo locally, use this guide to update your setup (click to expand)
If you already cloned the repo locally, you can update it to use the new setup. This assumes you have a local clone of the repo, the remote name is origin, and you have already forked the repo on GitHub.
# Getting a quick glance about your remotes: git remote -v
git remote -v
# Rename the existing remote to "upstream". Your "main" branch will now track "upstream/main"
git remote rename origin upstream
# Add your own fork as a remote, naming it "origin" (adjust the URL)
git remote add origin https://github.com/username/postgsail.git
Contributing New Code
# switch to main branch (tracking upstream/main), and pull the latest changes
git switch main
git fetch upstream
# create a new branch for your work
git switch -c my-new-feature
# edit files, and commit changes
# '-a' will add all modified files
# `-m` allows you to add a short commit message
git commit -a -m "My new feature"
# push the changes to your own fork
# '-u' will track your local branch with the remote
git push -u origin my-new-feature
# Click the link shown by `git push` in the terminal to create a pull request
# from your fork using the GitHub web interface