2026-04-19 20:33:56 -08:00
#!/bin/sh
DB_HOST = " ${ DB_HOST :- postgres } "
DB_USER = " ${ DB_USER :- drupal } "
DB_NAME = " ${ DB_NAME :- drupal } "
2026-05-25 14:40:17 -08:00
for var in SITE_NAME ADMIN_PASS; do
eval val = \$ $var
if [ -z " $val " ] ; then
echo " [entrypoint] FATAL: $var is required. "
exit 1
fi
done
2026-06-04 23:04:37 -08:00
chown -R www-data:www-data /var/www/html/web/sites/default/files
chmod -R 755 /var/www/html/web/sites/default/files
2026-04-19 20:33:56 -08:00
echo " [entrypoint] Waiting for PostgreSQL at ${ DB_HOST } ... "
until pg_isready -h " $DB_HOST " -U " $DB_USER " -d " $DB_NAME " -q; do
sleep 1
done
echo "[entrypoint] PostgreSQL is ready."
cd /var/www/html
DRUSH = "vendor/bin/drush --root=/var/www/html/web"
2026-05-27 20:58:19 -08:00
echo "[entrypoint] Preparing database..."
2026-04-19 20:33:56 -08:00
2026-05-27 20:58:19 -08:00
if [ " ${ DRUPAL_FAST :- } " = "1" ] ; then
echo "[entrypoint] DRUPAL_FAST=1 — skipping database wipe and full site reinstall."
else
echo "[entrypoint] Full rebuild mode (default). Dropping database..."
2026-06-11 21:25:31 -08:00
# DROP SCHEMA ... CASCADE is more reliable than drush sql:drop on PostgreSQL:
# it removes all tables atomically regardless of dependency order, so
# site:install always starts from a completely clean schema.
$DRUSH sql:query " DROP SCHEMA public CASCADE; CREATE SCHEMA public; GRANT ALL ON SCHEMA public TO ${ DB_USER } ; GRANT ALL ON SCHEMA public TO public; " || true
2026-05-27 20:58:19 -08:00
echo "[entrypoint] Installing Drupal (standard profile)..."
2026-05-12 16:28:47 -08:00
$DRUSH site:install standard \
2026-05-25 14:40:17 -08:00
--site-name= " $SITE_NAME " \
2026-04-19 20:33:56 -08:00
--account-name= admin \
2026-05-25 14:40:17 -08:00
--account-pass= " $ADMIN_PASS " \
2026-05-14 19:05:46 -08:00
-y || { echo "[entrypoint] FATAL: site:install failed." ; exit 1; }
2026-04-19 20:33:56 -08:00
echo "[entrypoint] Drupal installed."
2026-06-03 23:06:27 -08:00
2026-06-11 21:25:31 -08:00
$DRUSH sql:query "SELECT 1 FROM flood LIMIT 1" >/dev/null 2>& 1 \
|| { echo "[entrypoint] FATAL: flood table missing after site:install — schema incomplete." ; exit 1; }
2026-06-03 23:06:27 -08:00
# Clear semaphores immediately after fresh install (prevents early
# duplicate key errors during first module enables + rebuild).
$DRUSH sql:query "TRUNCATE TABLE semaphore;" 2>/dev/null || true
2026-05-14 19:05:46 -08:00
fi
2026-04-19 20:33:56 -08:00
2026-06-03 23:06:27 -08:00
# Always clear stale semaphores before module enables + rebuild.
# This is the most reliable way to avoid the duplicate key errors
# on "semaphore" (CacheCollector, cron, state locks, etc.).
$DRUSH sql:query "TRUNCATE TABLE semaphore;" 2>/dev/null || true
2026-05-25 14:40:17 -08:00
echo "[entrypoint] Enabling required modules..."
$DRUSH en -y views views_ui field_ui text options link datetime && \
echo "[entrypoint] Core modules enabled." || echo "[entrypoint] WARNING: core modules failed."
$DRUSH en -y webform webform_ui && \
echo "[entrypoint] Webform enabled." || echo "[entrypoint] WARNING: webform failed."
2026-06-04 23:37:56 -08:00
$DRUSH en -y symfony_mailer && \
2026-05-25 14:40:17 -08:00
echo "[entrypoint] Mailer enabled." || echo "[entrypoint] WARNING: symfony_mailer failed."
2026-06-04 22:22:43 -08:00
2026-06-04 23:37:56 -08:00
# Mail transport is configured via $config['system.mail']['mailer_dsn'] in settings.php,
# which is read directly by Drupal core's symfony_mailer mail plugin.
# Do NOT use the mailer_transport module's entity system for this — it is only a UI layer
# and is not consulted by core when actually sending mail.
2026-05-25 14:40:17 -08:00
$DRUSH en -y riverside_pt && \
echo "[entrypoint] riverside_pt enabled." || echo "[entrypoint] WARNING: riverside_pt failed."
2026-04-19 20:33:56 -08:00
2026-06-03 23:06:27 -08:00
# Clear semaphores to avoid duplicate key violations on the semaphore
# table (e.g. during CacheCollector, cron, state operations) that can
# occur during rapid config/entity changes in the rebuild.
$DRUSH sql:query "TRUNCATE TABLE semaphore;" 2>/dev/null || true
2026-05-27 20:58:19 -08:00
echo "[entrypoint] Rebuilding site structure from code (riverside:rebuild)..."
$DRUSH riverside:rebuild || echo "[entrypoint] WARNING: riverside:rebuild encountered an issue."
# Re-assert a few key pieces (cheap and safe).
2026-05-25 14:06:45 -08:00
$DRUSH theme:enable starterkit_theme claro_compact -y && \
$DRUSH config:set system.theme default starterkit_theme -y && \
$DRUSH config:set system.theme admin claro_compact -y && \
echo "[entrypoint] Themes set." || echo "[entrypoint] WARNING: theme enable failed."
2026-05-27 20:58:19 -08:00
2026-05-25 14:06:45 -08:00
$DRUSH config:set system.site page.front /home -y && \
echo "[entrypoint] Front page set." || echo "[entrypoint] WARNING: front page set failed."
2026-05-16 10:45:33 -08:00
npm run build --prefix /var/www/html >/dev/null 2>& 1 && echo "[entrypoint] Tailwind built." || echo "[entrypoint] WARNING: Tailwind build failed."
2026-06-03 23:06:27 -08:00
# One more semaphore clear before the final cache rebuild (common source
# of the duplicate key errors seen in logs).
$DRUSH sql:query "TRUNCATE TABLE semaphore;" 2>/dev/null || true
2026-05-14 20:23:54 -08:00
$DRUSH cache:rebuild >/dev/null 2>& 1 && echo "[entrypoint] Cache rebuilt."
2026-06-03 22:30:44 -08:00
if [ " ${ DEBUG :- false } " = "true" ] ; then
# Mock sendmail on localhost/dev: prints full email to stderr (visible in docker logs)
# instead of erroring with "sh: 1: /usr/sbin/sendmail: not found".
# This catches any php_mail / legacy mail() calls (e.g. some webforms, fallbacks).
# Real emails should still go via symfony_mailer + Postmark when configured.
Add email field to booking form + dev mail mocking
- Add required email input (with autocomplete="email") to the booking
details form in the homepage Preact widget (rpt-booking.js).
Update EMPTY_FORM, submit payload, confirmedAppointment, and success
summary to include it. The form now collects: first/last name, email,
phone, comments.
- Update ScheduleController::storeSlot to extract/pass email in the
booking_request mail params (and require it for the full-contact path).
Log failures with details; return a structured error with a user-friendly
message instead of bare "mail_failed".
- riverside_pt_mail hook now includes the user's email in the notification
body (when provided).
- Dev improvements for mail:
- In DEBUG mode (default on localhost), force php_mail interface in
settings.php so the mailer uses the sendmail_path override.
- Dockerfile + entrypoint.sh now provide/install a fake-sendmail.sh
that prints the full email (To, Subject, headers, body from the
hook) to stderr (visible in `docker compose logs`) and always
succeeds (exit 0). This prevents "sh: 1: /usr/sbin/sendmail: not
found" and guarantees booking submissions never return the
"unable to send confirmation email" error in dev.
- In non-DEBUG, still uses symfony_mailer + Postmark as before.
- The fake is also baked into the image for consistency.
- JS error handling now prefers the server-provided 'message' from
the JSON error response (better UX for real mail failures).
- Update CLAUDE.md with the new email field + dev mail mocking behavior.
- New file: docker/php/fake-sendmail.sh (the mock).
This addresses the recent "mail_failed" issues while keeping production
email via Postmark.
2026-06-03 22:05:06 -08:00
cat > /usr/local/bin/fake-sendmail.sh << 'FAKE_SENDMAIL'
#!/bin/sh
echo "=== MOCK SENDMAIL (dev - email logged, not sent) ===" >& 2
echo " Timestamp: $( date -Iseconds) " >& 2
echo " Called as: $0 $* " >& 2
echo "----- EMAIL CONTENT -----" >& 2
cat >& 2
echo "" >& 2
echo "=== END MOCK SENDMAIL ===" >& 2
exit 0
FAKE_SENDMAIL
chmod +x /usr/local/bin/fake-sendmail.sh
echo "[entrypoint] Installed fake sendmail for dev logging."
2026-06-03 22:30:44 -08:00
# Override sendmail_path for PHP (affects php_mail interface and any direct mail()).
echo 'sendmail_path = /usr/local/bin/fake-sendmail.sh' > /usr/local/etc/php/conf.d/sendmail.ini 2>/dev/null || true
else
# Ensure no dev mock leaks into prod: remove any sendmail_path override and the fake script.
rm -f /usr/local/etc/php/conf.d/sendmail.ini /usr/local/bin/fake-sendmail.sh 2>/dev/null || true
Add email field to booking form + dev mail mocking
- Add required email input (with autocomplete="email") to the booking
details form in the homepage Preact widget (rpt-booking.js).
Update EMPTY_FORM, submit payload, confirmedAppointment, and success
summary to include it. The form now collects: first/last name, email,
phone, comments.
- Update ScheduleController::storeSlot to extract/pass email in the
booking_request mail params (and require it for the full-contact path).
Log failures with details; return a structured error with a user-friendly
message instead of bare "mail_failed".
- riverside_pt_mail hook now includes the user's email in the notification
body (when provided).
- Dev improvements for mail:
- In DEBUG mode (default on localhost), force php_mail interface in
settings.php so the mailer uses the sendmail_path override.
- Dockerfile + entrypoint.sh now provide/install a fake-sendmail.sh
that prints the full email (To, Subject, headers, body from the
hook) to stderr (visible in `docker compose logs`) and always
succeeds (exit 0). This prevents "sh: 1: /usr/sbin/sendmail: not
found" and guarantees booking submissions never return the
"unable to send confirmation email" error in dev.
- In non-DEBUG, still uses symfony_mailer + Postmark as before.
- The fake is also baked into the image for consistency.
- JS error handling now prefers the server-provided 'message' from
the JSON error response (better UX for real mail failures).
- Update CLAUDE.md with the new email field + dev mail mocking behavior.
- New file: docker/php/fake-sendmail.sh (the mock).
This addresses the recent "mail_failed" issues while keeping production
email via Postmark.
2026-06-03 22:05:06 -08:00
fi
2026-05-24 18:23:05 -08:00
if [ " ${ DEBUG :- false } " = "true" ] ; then
NGINX_CSS_CACHE = 'expires off; add_header Cache-Control "no-store";'
else
NGINX_CSS_CACHE = 'expires max;'
fi
export NGINX_CSS_CACHE
envsubst '${NGINX_CSS_CACHE}' \
< /etc/nginx/conf.d/default.conf.template \
> /etc/nginx/conf.d/default.conf
echo " [entrypoint] nginx cache mode: ${ DEBUG :- false } = debug. "
2026-04-19 20:33:56 -08:00
echo "[entrypoint] Starting services..."
exec supervisord -c /etc/supervisor/conf.d/supervisord.conf