Sfoglia il codice sorgente

Fix: dev stack — css-watcher restart loop + readonly-DB 500

Two unrelated `make dev` regressions, both caused by the bind-mount
overlay clashing with how the upstream images expect to run:

* css-watcher restarted forever because Tailwind's `--watch` listens on
  stdin and exits on EOF; `compose up` closes stdin by default, so
  `restart: unless-stopped` looped it. Add `stdin_open` + `tty` to keep
  chokidar alive.
* The host bind mount at /var/www/data masks the Dockerfile's
  `chown www-data`, leaving app.sqlite (root:1000 644) and no sessions/
  dir, so the first request 500'd with "attempt to write a readonly
  database". Self-heal in the entrypoint by mkdir-ing the data + session
  dirs and chown-ing to www-data on every start (twice — migrate runs as
  root and would otherwise leave new SQLite/WAL files root-owned).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
ClaudePriv@chiappa.zhdk.ch 1 giorno fa
parent
commit
d1c3a0c0ec
2 ha cambiato i file con 20 aggiunte e 0 eliminazioni
  1. 13 0
      bin/docker-entrypoint.sh
  2. 7 0
      docker-compose.dev.yml

+ 13 - 0
bin/docker-entrypoint.sh

@@ -11,6 +11,7 @@
 set -euo pipefail
 
 APP_ROOT="${APP_ROOT:-/var/www/html}"
+DATA_PATH="${DATA_PATH:-/var/www/data}"
 # R01-N27: session-storage path (defaults match Dockerfile + .env.example).
 SESSION_PATH="${SESSION_PATH:-/var/www/data/sessions}"
 # R01-N27: session-file lifetime in minutes. Default 480 (= 8h), matching
@@ -20,9 +21,21 @@ SESSION_GC_MAX_AGE_MINUTES="${SESSION_GC_MAX_AGE_MINUTES:-480}"
 # R01-N27: how often to sweep, in seconds. Default 3600 (= once per hour).
 SESSION_GC_INTERVAL_SECONDS="${SESSION_GC_INTERVAL_SECONDS:-3600}"
 
+# Self-heal data-dir ownership: when a host bind mount is attached at
+# /var/www/data (dev compose) the host's uid/gid masks the Dockerfile's
+# `chown www-data` and SQLite + session writes fail with a confusing
+# "readonly database". Fix it on every start while we're still root —
+# once before migrate so it can open the DB, and once after, because
+# migrate runs as root and would otherwise leave new SQLite files
+# (and the WAL/SHM siblings) owned by root.
+mkdir -p "${DATA_PATH}" "${SESSION_PATH}"
+chown -R www-data:www-data "${DATA_PATH}"
+
 echo "[entrypoint] running deploy-time migrations…"
 php "${APP_ROOT}/bin/migrate.php"
 
+chown -R www-data:www-data "${DATA_PATH}"
+
 # R01-N27: PHP's built-in session GC fires probabilistically off request
 # traffic, so a low-traffic deployment keeps stale session files for days
 # past `gc_maxlifetime`. This backgrounded loop deletes session files

+ 7 - 0
docker-compose.dev.yml

@@ -36,6 +36,13 @@ services:
     # exports HOST_UID/HOST_GID; the :-1000 fallback covers the typical
     # case when someone invokes compose directly without going through make.
     user: "${HOST_UID:-1000}:${HOST_GID:-1000}"
+    # Tailwind's `--watch` mode listens on stdin and exits on EOF so a parent
+    # process closing the pipe terminates it cleanly. Under `compose up` stdin
+    # is closed by default, which makes the watcher exit 0 immediately and
+    # `restart: unless-stopped` then loops it. Keeping stdin open + a TTY
+    # attached lets chokidar actually start.
+    stdin_open: true
+    tty: true
     volumes:
       - ./assets:/build/assets
       - ./views:/build/views