Every dictionary entry now has a version: 16 hex digits of the SHA-256 of what cards take of it (headword, reading, entry), made by the loader and carried on every hit. A card keeps the version it took (card schema 8). DictionaryEndpoint.changed returns, of the entries named with the versions cards keep (1,000 at most a call; the app asks 500 at a time), those whose version is another now. The card browser says how many cards are behind their dictionary and takes the corrections at a tap (decided 2026-10-09: by offer, never by themselves). Taking one writes the entry as it is now over the revision in which the card last took it, beside whatever came after, so the revisions merge per side as two devices' edits do (ADR 0003): a side only the dictionary changed takes the correction, a side the person changed too is a conflict settled in the composer, whose words now name that case. Cards made before versions are never offered one. The server rereads its dictionary folder hourly now, not daily: the dictionaries service fills its volume after an instance's first start, and an hour with nothing changed costs a hash of each file. Migration 20261009145434785-dictionary-entry-version: adds dictionary_entry.version, text NOT NULL DEFAULT '' (rows loaded before have none and are never reported as corrected), and by hand empties dictionary_source."fileHash", so every source loads once more and its entries get their versions; the schema stays as definition.sql says. The old server goes on working until the switch. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MMm7usAo6q9ZZRoPkWjoxi Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
114 lines
4.5 KiB
YAML
114 lines
4.5 KiB
YAML
# The Halkyon Learn instance: Caddy in front, the Serverpod server, PostgreSQL, and
|
|
# the dictionaries kept current beside them.
|
|
#
|
|
# cd deploy
|
|
# cp .env.example .env && chmod 600 .env # then fill in the secrets
|
|
# docker compose up -d --build
|
|
#
|
|
# Only Caddy publishes ports. Docker opens published ports directly in the kernel's
|
|
# packet filter, past ufw, and the Serverpod server listens on every interface, so the
|
|
# server and Postgres publish nothing: they're reachable only inside this project's
|
|
# network, where Caddy finds the server by its service name.
|
|
|
|
name: halkyon-learn
|
|
|
|
# Logs go to the host's journal, whose size and age limits apply (journald.conf).
|
|
x-logging: &logging
|
|
driver: journald
|
|
|
|
services:
|
|
caddy:
|
|
image: caddy:2
|
|
restart: unless-stopped
|
|
ports:
|
|
- "80:80"
|
|
- "443:443"
|
|
- "443:443/udp" # HTTP/3
|
|
environment:
|
|
# `learn.halkyon.eu` on sahaquiel (automatic Let's Encrypt certificate);
|
|
# `http://localhost` for the local rehearsal (plain HTTP, no certificate).
|
|
DOMAIN: ${DOMAIN:?set DOMAIN in deploy/.env}
|
|
volumes:
|
|
- ./Caddyfile:/etc/caddy/Caddyfile:ro
|
|
- caddy_data:/data # certificates: must survive restarts (rate limits)
|
|
- caddy_config:/config
|
|
depends_on:
|
|
- server
|
|
logging: *logging
|
|
|
|
server:
|
|
build:
|
|
context: ..
|
|
dockerfile: halkyon_learn_server/Dockerfile
|
|
image: halkyon-learn-server
|
|
restart: unless-stopped
|
|
# Applies pending migrations at every start, then serves. One instance only, so
|
|
# no two servers ever migrate at once. (On learn.halkyon.eu, deploy/redeploy.sh has
|
|
# applied them in a run of their own before, so nothing is left to do here.)
|
|
command: ["--apply-migrations"]
|
|
environment:
|
|
SERVERPOD_DATABASE_PASSWORD: ${POSTGRES_PASSWORD:?set POSTGRES_PASSWORD in deploy/.env}
|
|
SERVERPOD_PASSWORD_serverSideSessionKeyHashPepper: ${SESSION_KEY_HASH_PEPPER:?set SESSION_KEY_HASH_PEPPER in deploy/.env}
|
|
# GitHub sign-in, only with this instance's GitHub OAuth app; empty: off.
|
|
SERVERPOD_PASSWORD_githubClientId: ${GITHUB_CLIENT_ID:-}
|
|
SERVERPOD_PASSWORD_githubClientSecret: ${GITHUB_CLIENT_SECRET:-}
|
|
# Where the source of what this instance runs is; empty: the project's.
|
|
SOURCE_URL: ${SOURCE_URL:-}
|
|
# How much room people's files may take, in MiB; empty: the defaults.
|
|
FILE_LIMIT_ANONYMOUS_MB: ${FILE_LIMIT_ANONYMOUS_MB:-}
|
|
FILE_LIMIT_IDENTIFIED_MB: ${FILE_LIMIT_IDENTIFIED_MB:-}
|
|
FILE_LIMIT_INSTANCE_MB: ${FILE_LIMIT_INSTANCE_MB:-}
|
|
# The dictionary files it loads at start and rereads hourly, those that changed
|
|
# (see the server's README): those the dictionaries service keeps current, read
|
|
# only. To supply files yourself instead, remove that service and mount
|
|
# ./dictionaries here (`- ./dictionaries:/app/dictionaries:ro`).
|
|
volumes:
|
|
- dictionaries:/app/dictionaries:ro
|
|
depends_on:
|
|
postgres:
|
|
condition: service_healthy
|
|
logging: *logging
|
|
|
|
# Keeps the dictionary files current from EDRDG's files of the day, once they are a
|
|
# week old (EDRDG's licence asks it of servers showing its dictionaries at least
|
|
# monthly; the curator's README): in a container of its own, the curator never in
|
|
# the server's image or process. It only downloads (some 25 MB a week) and writes
|
|
# into the volume; the files are never backed up, as they can be had again.
|
|
dictionaries:
|
|
build:
|
|
context: ..
|
|
dockerfile: halkyon_learn_curator/Dockerfile
|
|
image: halkyon-learn-dictionaries
|
|
restart: unless-stopped
|
|
# Docker's stop signal reaches the curator through a small init.
|
|
init: true
|
|
# A conversion takes some 400 MB for a minute a week.
|
|
mem_limit: 1g
|
|
volumes:
|
|
- dictionaries:/dictionaries
|
|
logging: *logging
|
|
|
|
postgres:
|
|
image: postgres:16
|
|
restart: unless-stopped
|
|
# The server's session is UTC anyway (the driver sets it); this makes the
|
|
# database's own default UTC too, for psql, COPY loads and future sidecars.
|
|
command: ["postgres", "-c", "timezone=UTC", "-c", "log_timezone=UTC"]
|
|
environment:
|
|
POSTGRES_USER: halkyon_learn
|
|
POSTGRES_DB: halkyon_learn
|
|
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?set POSTGRES_PASSWORD in deploy/.env}
|
|
volumes:
|
|
- postgres_data:/var/lib/postgresql/data
|
|
healthcheck:
|
|
test: ["CMD-SHELL", "pg_isready -U halkyon_learn -d halkyon_learn"]
|
|
interval: 5s
|
|
timeout: 5s
|
|
retries: 12
|
|
logging: *logging
|
|
|
|
volumes:
|
|
caddy_data:
|
|
caddy_config:
|
|
dictionaries:
|
|
postgres_data:
|