Adds a `dedup` task service under the "tools" profile so it's kept out of
`docker compose up` and run on demand:
docker compose run --rm dedup # hashes, then rebuild pairs
docker compose run --rm dedup -pairs # only rebuild pairs
docker compose run --rm dedup -hashes # only backfill hashes
It reuses the app image, .env, volumes and networks, overriding only the
entrypoint to /app/dedup. Unlike `docker exec` on the live server, this runs in
its own container and is self-documented for cron/CI use.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Bind the published port to 127.0.0.1 so the app is reachable only through the
host reverse proxy, not on the LAN/WAN — a 0.0.0.0 publish would also bypass
ufw/firewalld, since Docker's DNAT rules sit ahead of the host firewall.
Split the stack onto two networks with deterministic bridge names: `web`
(dk-tanabata) for the public-facing side, and `backend` (dk-tanabata-bnd,
internal:true) for the private app↔DB tier. The DB sits only on `backend`, which
has no gateway, so it has no route off-host.
Document TRUSTED_PROXIES and the loopback publish in .env.example.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Give the app service an explicit container_name so it shows up as `tfm`
instead of the generated `tanabata-app-1`.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Bundle the app + Postgres into a compose stack on top of the existing image.
- app: builds the image, publishes ${APP_PORT:-42776}, reads .env, pins
STATIC_DIR so SPA serving can't be disabled by an empty value
- db: postgres:14-alpine under the "with-db" profile; toggle it off via
COMPOSE_PROFILES to point the app at a Postgres on the host instead
(host.docker.internal), with depends_on required:false so it stays optional
Storage and the DB data dir each default to a named volume but can be bind
mounted to a host folder via FILES_DIR / THUMBS_DIR / IMPORT_DIR / DB_DIR.
Add PUID/PGID (via user:) so bind-mounted folders are writable by the
non-root container.
Run the container as a dedicated non-root user "tanabata" with uid/gid 42776,
reusing the project's signature number (also the default port). Document every
variable in .env.example.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>