feat(deploy): instances keep their dictionaries current, weekly, by themselves

EDRDG's licence asks of a server showing its dictionaries that it update
them at least monthly. The instance now does it alone: a `dictionaries`
service in compose, built from the curator (halkyon_learn_curator/
Dockerfile, its own unprivileged user 10001, 1 GB at most), runs `curate
update --every 7`, downloading EDRDG's files of the day once its files are
a week old and replacing them in a volume the server mounts read-only.
The curator never enters the server's image or process (decided
2026-10-09: a container of its own, weekly). The server rereads the
folder daily at 04:07 (DictionaryReloadFutureCall), loading what changed,
and loads now run one at a time. redeploy.sh builds both images.

An operator who'd rather supply the files removes the service and mounts
deploy/dictionaries/ into the server, as compose.yaml says.

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>
This commit is contained in:
Tizian 「ティツィアーン」 2026-10-09 16:52:37 +02:00
commit 25e01ad128
Signed by: raisondetredev
GPG key ID: 07F6FCF405488B64

View file

@ -0,0 +1,51 @@
# The dictionaries' image: the curator, keeping a server's dictionary files current
# from EDRDG's files of the day (`curate update`, the README). Built from the
# repository root (the build context), where the workspace's root pubspec and lockfile
# live:
#
# docker build -f halkyon_learn_curator/Dockerfile .
#
# A container of its own beside the server (deploy/compose.yaml, decided 2026-10-09):
# the curator (AGPL) never enters the server's image or process, and a conversion
# that fails can't touch the server. They share only the folder of files.
# ── Build stage: compile the curator to a native executable ───────────────────────
FROM dart:3.13.4 AS build
WORKDIR /app
COPY pubspec.yaml pubspec.lock ./
COPY halkyon_learn_curator halkyon_learn_curator
# The workspace root with only the curator package, as the server's Dockerfile does it
# with the server's. The check fails the build loudly if the member list changes shape.
RUN sed -i -e '/^ - halkyon_learn_client$/d' -e '/^ - halkyon_learn_flutter$/d' \
-e '/^ - halkyon_learn_server$/d' pubspec.yaml \
&& grep -q '^ - halkyon_learn_curator$' pubspec.yaml \
&& ! grep -q -e 'halkyon_learn_client' -e 'halkyon_learn_flutter' \
-e 'halkyon_learn_server' pubspec.yaml
RUN dart pub get
WORKDIR /app/halkyon_learn_curator
RUN dart build cli --target bin/curate.dart --output build
# ── Runtime stage ─────────────────────────────────────────────────────────────────
# Ubuntu 24.04 as the server's, with CA certificates for EDRDG's HTTPS.
FROM ubuntu:24.04
RUN apt-get update \
&& apt-get install -y --no-install-recommends ca-certificates \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /app
COPY --from=build /app/halkyon_learn_curator/build/bundle/ ./
COPY --from=build /app/halkyon_learn_curator/data/ data/
# An unprivileged user of its own: user ID 10001, shared with neither the containers
# of PostgreSQL and the server (999) nor the CI runner on the host (61000). The folder
# it writes into belongs to it, which a new volume mounted there takes over.
RUN useradd --system --uid 10001 --no-create-home --shell /usr/sbin/nologin curator \
&& mkdir /dictionaries \
&& chown curator /dictionaries
USER curator
# Updates the files whenever they are a week old (EDRDG's licence asks at least
# monthly), and sleeps in between.
ENTRYPOINT ["./bin/curate", "update", "--into", "/dictionaries", "--data", "data"]
CMD ["--every", "7"]