2026-10-29 00:05:39 +01:00
|
|
|
# Halkyon Train's server beside the instance (ADR 0030, D46), with the BRouter that
|
|
|
|
|
# plans its routes (D11, D44). Switched on in .env, with Train's domain and secrets:
|
|
|
|
|
#
|
2026-11-02 22:06:18 +01:00
|
|
|
# COMPOSE_FILE=compose.learn.yaml:compose.train.yaml
|
2026-10-29 00:05:39 +01:00
|
|
|
# TRAIN_DOMAIN=train.halkyon.eu
|
|
|
|
|
#
|
|
|
|
|
# Train is a member of the instance's register, which Learn's server holds (ADR 0016):
|
|
|
|
|
# one account a person, signing in through the register, the shared INSTANCE_SECRET
|
|
|
|
|
# on every call between them, which reach each other on the instance's own networks
|
|
|
|
|
# alone. Its database is `halkyon_train` in the instance's PostgreSQL, under a role of
|
|
|
|
|
# its own that can't connect to Learn's. BRouter has no site and no sign-in: only
|
|
|
|
|
# Train's server reaches it, on a network of their own, and asks it nothing that is
|
|
|
|
|
# logged. Its segments (Europe's, about 3.3 GB) are in ./brouter/segments, which the
|
|
|
|
|
# refresher keeps current monthly, owned by a user ID of their own, which no person,
|
|
|
|
|
# no other container and not the CI runner uses. Setting it up: sidecars/README.md.
|
|
|
|
|
|
|
|
|
|
services:
|
|
|
|
|
train-server:
|
|
|
|
|
build:
|
|
|
|
|
context: ..
|
|
|
|
|
dockerfile: apps/train/halkyon_train_server/Dockerfile
|
|
|
|
|
image: halkyon-train-server
|
|
|
|
|
restart: unless-stopped
|
|
|
|
|
# As Learn's: migrations at every start (redeploy.sh has applied them before).
|
|
|
|
|
command: ["--apply-migrations"]
|
|
|
|
|
environment:
|
|
|
|
|
SERVERPOD_DATABASE_PASSWORD: ${TRAIN_POSTGRES_PASSWORD:?set TRAIN_POSTGRES_PASSWORD in deploy/.env}
|
|
|
|
|
SERVERPOD_PASSWORD_serverSideSessionKeyHashPepper: ${TRAIN_SESSION_KEY_HASH_PEPPER:?set TRAIN_SESSION_KEY_HASH_PEPPER in deploy/.env}
|
|
|
|
|
# The register (ADR 0016): Learn's web server, on the instance's own network,
|
|
|
|
|
# and the secret every call between them carries.
|
|
|
|
|
ACCOUNT_REGISTER_URL: http://server:8082/
|
|
|
|
|
SERVERPOD_PASSWORD_instanceSecret: ${INSTANCE_SECRET:?set INSTANCE_SECRET in deploy/.env}
|
2026-11-02 22:06:18 +01:00
|
|
|
# Caddy, as for Learn's server (compose.learn.yaml).
|
2026-10-29 00:05:39 +01:00
|
|
|
TRUSTED_PROXIES: 172.30.80.2 fd4a:6c6b:7e80::2
|
|
|
|
|
SOURCE_URL: ${SOURCE_URL:-}
|
|
|
|
|
DATA_LOCATION: ${DATA_LOCATION:-}
|
|
|
|
|
BACKUP_LOCATION: ${BACKUP_LOCATION:-}
|
|
|
|
|
# Routes (D44), from the BRouter below.
|
|
|
|
|
BROUTER_URL: http://brouter:17777/
|
|
|
|
|
# The Loop's firmware through the instance (D40): on unless `off`.
|
|
|
|
|
LOOP_FIRMWARE_RELAY: ${LOOP_FIRMWARE_RELAY:-}
|
feat(train): workouts' weather from Open-Meteo, through the instance (ADR 0036)
A workout with a track gets the weather over it as its page opens, once
while it has none: the hours from the one it started in to the one it
ended in, kept in its sealed payload (temperature, feels-like, humidity,
precipitation, the WMO code, the wind, its gusts and direction) and shown
under its totals with the link to Open-Meteo its licence asks for.
Train's server asks Open-Meteo in the person's place (the `weather`
endpoint), so Open-Meteo never sees their address: the place rounded to
two decimals (also on the phone), a span of at most 48 hours, the
forecast API for recent spans and the archive for older ones, for people
signed in, at most 30 requests a person a minute, nothing kept or
logged. On by default; `WEATHER=off` switches it off, and
`OPEN_METEO_API_KEY` moves it to the paid hosts for an instance used
commercially.
Health Connect's fingerprint leaves the weather out, so keeping it
writes nothing again. No table and no migration.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-02 13:59:41 +01:00
|
|
|
# Workouts' weather from Open-Meteo (ADR 0036): on unless `off`; a key
|
|
|
|
|
# for its paid hosts where the instance is used commercially.
|
|
|
|
|
WEATHER: ${WEATHER:-}
|
|
|
|
|
OPEN_METEO_API_KEY: ${OPEN_METEO_API_KEY:-}
|
2026-10-29 00:05:39 +01:00
|
|
|
# The map source (D22); empty: OpenFreeMap.
|
|
|
|
|
MAP_STYLE_URL: ${MAP_STYLE_URL:-}
|
2026-11-04 20:44:47 +01:00
|
|
|
MAP_DARK_STYLE_URL: ${MAP_DARK_STYLE_URL:-}
|
2026-10-29 00:05:39 +01:00
|
|
|
MAP_SOURCE_NAME: ${MAP_SOURCE_NAME:-}
|
|
|
|
|
MAP_ATTRIBUTION: ${MAP_ATTRIBUTION:-}
|
|
|
|
|
MAP_ABOUT_URL: ${MAP_ABOUT_URL:-}
|
|
|
|
|
networks:
|
|
|
|
|
- default
|
|
|
|
|
- edge
|
|
|
|
|
- routing
|
|
|
|
|
depends_on:
|
|
|
|
|
postgres:
|
|
|
|
|
condition: service_healthy
|
|
|
|
|
logging:
|
|
|
|
|
driver: journald
|
|
|
|
|
|
|
|
|
|
brouter:
|
|
|
|
|
build:
|
|
|
|
|
context: ..
|
|
|
|
|
dockerfile: deploy/brouter/Dockerfile
|
|
|
|
|
image: halkyon-brouter
|
|
|
|
|
restart: unless-stopped
|
|
|
|
|
user: "61177:61177"
|
|
|
|
|
read_only: true
|
|
|
|
|
tmpfs:
|
|
|
|
|
- /tmp:size=16m,uid=61177,gid=61177
|
|
|
|
|
volumes:
|
|
|
|
|
- ./brouter/segments:/segments4:ro
|
|
|
|
|
# Beside Train's server alone: no site, no published port, never beside Caddy or
|
|
|
|
|
# Postgres.
|
|
|
|
|
networks:
|
|
|
|
|
- routing
|
|
|
|
|
mem_limit: 640m
|
|
|
|
|
# No log at all: BRouter writes each route's waypoints to its output, and where
|
|
|
|
|
# people run must never be kept. To look into a failure, switch to journald for
|
|
|
|
|
# a while.
|
|
|
|
|
logging:
|
|
|
|
|
driver: none
|
|
|
|
|
|
|
|
|
|
brouter-segments:
|
|
|
|
|
image: halkyon-brouter
|
|
|
|
|
restart: unless-stopped
|
|
|
|
|
user: "61177:61177"
|
|
|
|
|
read_only: true
|
|
|
|
|
command: ["/app/segments.sh"]
|
|
|
|
|
environment:
|
|
|
|
|
# `west,south,east,north` of the segments' south-west corners; Europe's.
|
|
|
|
|
BROUTER_REGION: ${BROUTER_REGION:--25,35,40,70}
|
|
|
|
|
volumes:
|
|
|
|
|
- ./brouter/segments:/segments4
|
2026-10-30 12:55:42 +01:00
|
|
|
# Out to brouter.de on `downloads`, an ordinary bridge with a way out to anywhere,
|
|
|
|
|
# shared with the map's and the search's downloads where their compose files are on.
|
2026-10-29 00:05:39 +01:00
|
|
|
networks:
|
|
|
|
|
- downloads
|
|
|
|
|
mem_limit: 64m
|
|
|
|
|
logging:
|
|
|
|
|
driver: journald
|
|
|
|
|
|
|
|
|
|
caddy:
|
|
|
|
|
environment:
|
|
|
|
|
TRAIN_DOMAIN: ${TRAIN_DOMAIN:?set TRAIN_DOMAIN in deploy/.env}
|
|
|
|
|
volumes:
|
|
|
|
|
- ./sidecars/train.caddy:/etc/caddy/sidecars/train.caddy:ro
|
|
|
|
|
|
|
|
|
|
server:
|
|
|
|
|
environment:
|
build(todo): Todo deployable beside Learn's server, and released as an APK, on F-Droid and as a snap (ADR 0033, step 5)
deploy/compose.todo.yaml adds Todo's server at todo.halkyon.eu, a member
of Learn's register, its database halkyon_todo in the instance's
PostgreSQL, its image built as Train's. redeploy.sh and backup.sh go over
every app server .env switches on (train, todo). Each compose file names
its server to the register in a variable of its own
(INSTANCE_MEMBER_TRAIN, INSTANCE_MEMBER_TODO), which halkyon_base adds to
INSTANCE_MEMBERS, each address once, as a second compose file's default
would have replaced Train's.
apps/todo/release.dart configures the release tool for Todo's APK and
snap: a key of its own (pinned once made; until then nothing is
released), the F-Droid listing (Time, NonFreeNet), and the snap from
apps/todo/snap/, which the tool builds in a clone of the repository at the
tag with that folder in place of snap/, as snapcraft builds one recipe a
folder and the root's is Learn's. What's new for 0.1.0 in English and
German, now shown. Android's backup and transfer are off, as Train's
(D53): the reminders scheduled keep their tasks' titles unsealed.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-02 15:35:40 +01:00
|
|
|
# Train's web server, told when an account goes (ADR 0016), beside the members
|
|
|
|
|
# the other compose files and INSTANCE_MEMBERS name.
|
|
|
|
|
INSTANCE_MEMBER_TRAIN: http://train-server:8082/
|
2026-10-29 00:05:39 +01:00
|
|
|
|
|
|
|
|
networks:
|
|
|
|
|
# Train's server and BRouter, without a way out.
|
|
|
|
|
routing:
|
|
|
|
|
internal: true
|
|
|
|
|
downloads:
|