| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081 |
- # --- Stage 1: compile Tailwind CSS + vendor JS deps ----------------------
- # Runs the Tailwind JIT over views/, src/, and our JS so only classes that
- # are actually referenced end up in the output. No runtime <style> injection,
- # which lets the CSP drop 'unsafe-inline' for style-src.
- #
- # The same stage also vendors Alpine.js (CSP build), htmx, and SortableJS
- # from npm into /build/vendor/ — copied into the runtime image alongside the
- # CSS so the strict CSP can keep `script-src 'self'`.
- FROM node:20-alpine AS css-builder
- WORKDIR /build
- COPY package.json package-lock.json* ./
- RUN npm ci --no-audit --no-fund
- # Only the files that contribute to class discovery / the entry stylesheet.
- COPY tailwind.config.js ./
- COPY assets/css/input.css ./assets/css/input.css
- COPY views/ ./views/
- COPY src/ ./src/
- COPY public/assets/js/ ./public/assets/js/
- RUN npx tailwindcss -i ./assets/css/input.css -o /build/app.css --minify
- # Pin the vendored JS bundles. Alpine CSP is the variant that doesn't need
- # `unsafe-eval`; standard Alpine would require relaxing the CSP.
- RUN mkdir -p /build/vendor \
- && cp node_modules/@alpinejs/csp/dist/cdn.min.js /build/vendor/alpine-csp.min.js \
- && cp node_modules/htmx.org/dist/htmx.min.js /build/vendor/htmx.min.js \
- && cp node_modules/sortablejs/Sortable.min.js /build/vendor/sortable.min.js
- # --- Stage 2: the actual PHP runtime ------------------------------------
- FROM php:8.3-apache
- RUN apt-get update && apt-get install -y --no-install-recommends \
- libsqlite3-dev libzip-dev libpng-dev libjpeg-dev libfreetype6-dev unzip git \
- && docker-php-ext-configure gd --with-freetype --with-jpeg \
- && docker-php-ext-install pdo pdo_sqlite zip gd \
- && a2enmod rewrite \
- && rm -rf /var/lib/apt/lists/*
- COPY --from=composer:2 /usr/bin/composer /usr/bin/composer
- WORKDIR /var/www/html
- COPY composer.json composer.lock* ./
- RUN composer install --no-dev --no-interaction --prefer-dist --no-progress
- COPY . .
- # Place the compiled CSS + vendored JS where Apache can serve them.
- COPY --from=css-builder /build/app.css /var/www/html/public/assets/css/app.css
- COPY --from=css-builder /build/vendor/ /var/www/html/public/assets/js/vendor/
- # Twig cache lives under data/ alongside the SQLite file. www-data must be
- # able to write there at request time so first-render template compilation
- # succeeds.
- RUN mkdir -p /var/www/data /var/www/data/sessions /var/www/html/data/twig-cache \
- && chown -R www-data:www-data /var/www/data /var/www/html/data \
- && printf '%s\n' \
- '<VirtualHost *:80>' \
- ' DocumentRoot /var/www/html/public' \
- ' <Directory /var/www/html/public>' \
- ' Options -Indexes +FollowSymLinks' \
- ' AllowOverride All' \
- ' Require all granted' \
- ' FallbackResource /index.php' \
- ' </Directory>' \
- ' ErrorLog ${APACHE_LOG_DIR}/error.log' \
- ' CustomLog ${APACHE_LOG_DIR}/access.log combined' \
- '</VirtualHost>' \
- > /etc/apache2/sites-available/000-default.conf
- # R01-N22: run migrations at container start, before Apache binds the port.
- # The request path no longer auto-migrates — it only checks and refuses to
- # serve when something is pending — so a missed entrypoint produces a loud
- # 503, not silent stale-schema serving.
- RUN install -m 0755 /var/www/html/bin/docker-entrypoint.sh /usr/local/bin/docker-entrypoint.sh
- EXPOSE 80
- ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh"]
- CMD ["apache2-foreground"]
|