Skip to content

feat: complete the Docker setup — wire the compose stack, add a PHP 8.4 CLI image (IP-149)#601

Closed
nielsdrost7 wants to merge 2 commits into
developfrom
feature/149-docker-cli-image
Closed

feat: complete the Docker setup — wire the compose stack, add a PHP 8.4 CLI image (IP-149)#601
nielsdrost7 wants to merge 2 commits into
developfrom
feature/149-docker-cli-image

Conversation

@nielsdrost7

@nielsdrost7 nielsdrost7 commented Jul 13, 2026

Copy link
Copy Markdown
Collaborator

Completes the standalone Docker setup from feature/149-docker-setup (issue #149) and adds the missing piece: a CLI image so users and contributors can run the test suite, artisan, and composer with no PHP on the host.

What this adds on top of the existing branch

  1. docker-resources/php-cli/Dockerfile — PHP 8.4 CLI (alpine), the exact extension twin of the existing php-fpm image (intl, gd, pdo_mysql, bcmath, zip, exif, soap, redis) plus Composer, a 1G memory limit (the full suite OOMs at the 128M default), and bundled pdo_sqlite — the test suite runs on in-memory sqlite, so tests need zero services. UID/GID build args let Linux users match host ownership for files written into the mounted repo (vendor/, storage/) — this exact mismatch produces hundreds of confusing tempnam() test errors otherwise.
  2. docker-compose.yml actually wires the images in. The branch shipped apache + php-fpm Dockerfiles but the compose file only started db + mailcatcher, and DOCKER.md referenced an app container that didn't exist. Now: web (apache, port ${APP_PORT:-8080}) → app (php-fpm, matching the vhost's fcgi://app:9000) → db, plus the new cli service behind a tools profile so it never auto-starts.
  3. .github/DOCKER.md rewritten to match reality — corrected clone URL (pointed at v1's repo), a services table, a no-host-PHP quick start, test-suite instructions, and the UID/GID troubleshooting entry.

Why a CLI image at all

The vendor tree requires PHP ≥ 8.3 with intl + gd; typical host PHPs miss at least one of those (Filament table rendering hard-requires intl, dompdf wants gd). This image is the supported, reproducible way to run vendor/bin/phpunit — validated by developing the Report Builder with a hand-rolled equivalent of exactly this image.

Verified

  • docker compose config valid; --profile tools exposes cli alongside the five services
  • CLI image builds clean; php -m shows the full extension set; composer --version works
  • Test suite executes through docker compose run --rm cli vendor/bin/phpunit (sqlite in-memory). Note: some company-panel tests fail on this branch's lineage because it predates the permission-seeding fixes on develop — pre-existing to this PR; the same command is fully green on branches that include those fixes.
  • Web stack (web + app) is config-validated against the existing vhost (fcgi://app:9000, docroot htdocs/public); it still needs a bootstrapped .env + key to serve, per DOCKER.md's quick start.

Closes #149

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added a dedicated CLI container for running Composer, Artisan commands, migrations, and PHPUnit tests.
    • Added streamlined Docker services for the web application, PHP runtime, database, and mail testing.
    • Improved Apache and PHP-FPM configuration for serving the application through Docker.
    • Added Docker-based frontend development support with Vite and hot module replacement.
  • Documentation

    • Reworked the Docker guide with updated setup steps, service details, commands, testing instructions, and troubleshooting guidance.
    • Added guidance for Linux file permissions and configurable application ports.

nielsdrost7 and others added 2 commits June 12, 2026 22:23
…lopment

Brings in custom Dockerfiles for PHP-FPM, Apache, and Node from the
original feature/docker-env branch, ported cleanly onto develop.

- docker-resources/php-fpm/Dockerfile  — PHP 8.4-fpm-alpine with all
  required extensions (pdo_mysql, gd, intl, redis, opcache, etc.)
- docker-resources/apache/Dockerfile   — Apache 2.4 with PHP-FPM proxy
- docker-resources/apache/config/invoiceplane-vhost.conf
- docker-resources/node/scripts/entrypoint.sh — Vite dev server with
  Docker-aware path and HMR configuration

Refs #149

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The branch shipped apache and php-fpm Dockerfiles that docker-compose.yml
never started, and DOCKER.md described an app container that did not
exist. The compose file now runs web (apache, APP_PORT with 8080
default) -> app (php-fpm, matching the vhost's fcgi://app:9000) -> db,
plus mailcatcher.

Adds docker-resources/php-cli: a CLI twin of the php-fpm image (same
extension set: intl, gd, pdo_mysql, bcmath, zip, exif, soap, redis)
with Composer, a 1G memory limit for the test suite, and UID/GID build
args so files written into the mounted repo keep host ownership. It
runs behind a "tools" compose profile as a one-off runner:

    docker compose run --rm cli vendor/bin/phpunit

The test suite runs on in-memory sqlite, so tests need no services at
all. DOCKER.md rewritten to match (correct v2 clone URL, services
table, no-host-PHP quick start, ownership troubleshooting).

Refs #149

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

The Docker setup adds PHP CLI and FPM images, Apache PHP-FPM proxying, Docker-specific Vite startup, Compose services and networking, and updated documentation for startup, testing, ownership, commands, and troubleshooting.

Changes

Docker development stack

Layer / File(s) Summary
Runtime images and tooling
docker-resources/php-cli/Dockerfile, docker-resources/php-fpm/Dockerfile, docker-resources/apache/*, docker-resources/node/scripts/entrypoint.sh
Adds PHP 8.4 CLI/FPM images, Apache PHP-FPM routing, and Docker-specific Vite configuration and startup.
Compose service orchestration
docker-compose.yml
Defines app, web, and profile-gated cli services, and connects database and mailcatcher services to the laravel network.
Developer workflows
.github/DOCKER.md
Documents Docker startup, CLI-based Artisan and PHPUnit commands, file ownership configuration, useful commands, and troubleshooting steps.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant DockerCompose
  participant web
  participant app
  participant db
  DockerCompose->>web: start web service and expose APP_PORT
  web->>app: proxy PHP requests to app:9000
  app->>db: connect through laravel network
  DockerCompose->>db: attach db to laravel network
Loading

Suggested reviewers: khawarmehfooz

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning Issue #149 is only partially met: Redis, a Node/Vite service, .env.docker, and the README quick-start are not shown in these changes. Add redis and node services to compose, provide a .env.docker example, and move the Docker quick-start into the README.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main Docker compose and PHP 8.4 CLI additions.
Out of Scope Changes check ✅ Passed The changes stay focused on Docker infrastructure, documentation, and container tooling needed for local development.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/149-docker-cli-image

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (2)
docker-compose.yml (1)

14-15: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Consider a health-conditioned depends_on for the db service.

The app service starts as soon as the db container launches, but MariaDB may not be ready to accept connections yet. Laravel retries, so this works in practice, but the app logs spurious connection errors during initial startup. Adding a healthcheck on db and using condition: service_healthy would provide a cleaner startup.

Proposed change
     depends_on:
-        - db
+        db:
+            condition: service_healthy

And add a health check to the db service (outside the changed range):

    db:
        ...
        healthcheck:
            test: ["CMD-SHELL", "mariadb-admin ping -h localhost -u root -p$$MYSQL_ROOT_PASSWORD || exit 1"]
            interval: 3s
            timeout: 3s
            retries: 10
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docker-compose.yml` around lines 14 - 15, Update the app service’s depends_on
configuration to use the db service with condition service_healthy, and add the
specified healthcheck under the db service using mariadb-admin ping with the
existing root password, 3-second interval and timeout, and 10 retries.
docker-resources/php-cli/Dockerfile (1)

13-55: 📐 Maintainability & Code Quality | 🔵 Trivial | 🏗️ Heavy lift

Extension installation block is duplicated across both PHP Dockerfiles. The build-dependency, runtime-dependency, PHP extension, and PECL redis installation steps are nearly identical in both images, creating a maintenance burden where any extension or package change must be applied in two places.

  • docker-resources/php-cli/Dockerfile#L13-L55: Extract the shared install steps into a common base image (e.g., php:8.4-alpine with extensions pre-installed) or a reusable shell script that both Dockerfiles COPY and RUN.
  • docker-resources/php-fpm/Dockerfile#L6-L47: Same — consume the shared base image or script instead of maintaining a separate copy.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docker-resources/php-cli/Dockerfile` around lines 13 - 55, Deduplicate the
shared PHP dependency and extension installation logic used by the Dockerfiles:
in docker-resources/php-cli/Dockerfile lines 13-55 and
docker-resources/php-fpm/Dockerfile lines 6-47, extract the build dependencies,
runtime packages, PHP extensions, and PECL redis setup into a common base image
or reusable script, then make both Dockerfiles consume it while preserving their
image-specific steps.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docker-resources/node/scripts/entrypoint.sh`:
- Around line 1-18: Add `set -e` immediately after the shebang in the entrypoint
script so failures from `mkdir`, `cp`, or either `sed` command terminate
execution before reaching the npm install and Vite startup command.

In `@docker-resources/php-fpm/Dockerfile`:
- Line 3: Update the PHP-FPM Dockerfile user setup to declare and use
configurable UID and GID build arguments, matching the existing CLI Dockerfile
pattern instead of hardcoding dockeruser’s IDs. Update the app service in
docker-compose.yml to pass the host-aligned UID and GID build arguments through
to the FPM image.

---

Nitpick comments:
In `@docker-compose.yml`:
- Around line 14-15: Update the app service’s depends_on configuration to use
the db service with condition service_healthy, and add the specified healthcheck
under the db service using mariadb-admin ping with the existing root password,
3-second interval and timeout, and 10 retries.

In `@docker-resources/php-cli/Dockerfile`:
- Around line 13-55: Deduplicate the shared PHP dependency and extension
installation logic used by the Dockerfiles: in
docker-resources/php-cli/Dockerfile lines 13-55 and
docker-resources/php-fpm/Dockerfile lines 6-47, extract the build dependencies,
runtime packages, PHP extensions, and PECL redis setup into a common base image
or reusable script, then make both Dockerfiles consume it while preserving their
image-specific steps.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: be3f85f5-2a8b-4d92-8089-dcd455da8036

📥 Commits

Reviewing files that changed from the base of the PR and between 93ec359 and bd71fad.

📒 Files selected for processing (7)
  • .github/DOCKER.md
  • docker-compose.yml
  • docker-resources/apache/Dockerfile
  • docker-resources/apache/config/invoiceplane-vhost.conf
  • docker-resources/node/scripts/entrypoint.sh
  • docker-resources/php-cli/Dockerfile
  • docker-resources/php-fpm/Dockerfile

Comment on lines +1 to +18
#!/bin/sh

# Copy original vite.config.js to Docker-specific version
mkdir -p /app/.docker
cp /app/vite.config.js /app/.docker/vite.config.docker.js

# Update resource paths to absolute paths
sed -i "s|'resources/css/app.css'|'/app/resources/css/app.css'|g" /app/.docker/vite.config.docker.js
sed -i "s|'resources/js/app.js'|'/app/resources/js/app.js'|g" /app/.docker/vite.config.docker.js

# Add Docker-specific server configuration if not already present
if ! grep -q "server:" /app/.docker/vite.config.docker.js; then
# Insert server config before the closing }); of defineConfig
sed -i '/^});$/i\ server: {\n host: '\''0.0.0.0'\'',\n port: 5173,\n hmr: {\n host: '\''localhost'\'',\n },\n },' /app/.docker/vite.config.docker.js
fi

# Install dependencies and start Vite with Docker config
npm install && npm run dev -- --config .docker/vite.config.docker.js

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Add set -e to fail fast on copy/sed errors.

Without set -e, if cp or sed fails (e.g., vite.config.js missing), the script continues to npm install && npm run dev, which fails with a confusing "config file not found" error instead of surfacing the original failure.

Proposed fix
 #!/bin/sh
+set -e
+
 # Copy original vite.config.js to Docker-specific version
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
#!/bin/sh
# Copy original vite.config.js to Docker-specific version
mkdir -p /app/.docker
cp /app/vite.config.js /app/.docker/vite.config.docker.js
# Update resource paths to absolute paths
sed -i "s|'resources/css/app.css'|'/app/resources/css/app.css'|g" /app/.docker/vite.config.docker.js
sed -i "s|'resources/js/app.js'|'/app/resources/js/app.js'|g" /app/.docker/vite.config.docker.js
# Add Docker-specific server configuration if not already present
if ! grep -q "server:" /app/.docker/vite.config.docker.js; then
# Insert server config before the closing }); of defineConfig
sed -i '/^});$/i\ server: {\n host: '\''0.0.0.0'\'',\n port: 5173,\n hmr: {\n host: '\''localhost'\'',\n },\n },' /app/.docker/vite.config.docker.js
fi
# Install dependencies and start Vite with Docker config
npm install && npm run dev -- --config .docker/vite.config.docker.js
#!/bin/sh
set -e
# Copy original vite.config.js to Docker-specific version
mkdir -p /app/.docker
cp /app/vite.config.js /app/.docker/vite.config.docker.js
# Update resource paths to absolute paths
sed -i "s|'resources/css/app.css'|'/app/resources/css/app.css'|g" /app/.docker/vite.config.docker.js
sed -i "s|'resources/js/app.js'|'/app/resources/js/app.js'|g" /app/.docker/vite.config.docker.js
# Add Docker-specific server configuration if not already present
if ! grep -q "server:" /app/.docker/vite.config.docker.js; then
# Insert server config before the closing }); of defineConfig
sed -i '/^});$/i\ server: {\n host: '\''0.0.0.0'\'',\n port: 5173,\n hmr: {\n host: '\''localhost'\'',\n },\n },' /app/.docker/vite.config.docker.js
fi
# Install dependencies and start Vite with Docker config
npm install && npm run dev -- --config .docker/vite.config.docker.js
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docker-resources/node/scripts/entrypoint.sh` around lines 1 - 18, Add `set
-e` immediately after the shebang in the entrypoint script so failures from
`mkdir`, `cp`, or either `sed` command terminate execution before reaching the
npm install and Vite startup command.

@@ -0,0 +1,58 @@
FROM php:8.4-fpm-alpine

RUN adduser -D -s /bin/bash dockeruser

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

FPM container lacks configurable UID/GID.

The CLI Dockerfile accepts ARG UID / ARG GID so the container user can match the host user, but the FPM Dockerfile hardcodes adduser -D -s /bin/bash dockeruser (default UID 1000). The FPM process writes to storage/ and bootstrap/cache/ on the mounted volume; if the host user's UID differs, those files will be owned by UID 1000 and may be unwritable or unmanageable by the host user. Apply the same ARG UID / ARG GID pattern here, and pass build args from the app service in docker-compose.yml.

Proposed fix
+ARG UID=1000
+ARG GID=1000
+
+RUN addgroup -g ${GID} dockeruser \
+    && adduser -D -s /bin/bash -u ${UID} -G dockeruser dockeruser
-RUN adduser -D -s /bin/bash dockeruser

And in docker-compose.yml:

     app:
         container_name: 'ivplflmnt_app'
         build:
             context: ./docker-resources/php-fpm
+            args:
+                UID: ${UID:-1000}
+                GID: ${GID:-1000}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
RUN adduser -D -s /bin/bash dockeruser
ARG UID=1000
ARG GID=1000
RUN addgroup -g ${GID} dockeruser \
&& adduser -D -s /bin/bash -u ${UID} -G dockeruser dockeruser
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docker-resources/php-fpm/Dockerfile` at line 3, Update the PHP-FPM Dockerfile
user setup to declare and use configurable UID and GID build arguments, matching
the existing CLI Dockerfile pattern instead of hardcoding dockeruser’s IDs.
Update the app service in docker-compose.yml to pass the host-aligned UID and
GID build arguments through to the FPM image.

@nielsdrost7

Copy link
Copy Markdown
Collaborator Author

Recreated as #611 with the head branch on the fork (underdogg-forks) per the repo workflow — development on the fork, PRs land here. Same commits.

@nielsdrost7 nielsdrost7 deleted the feature/149-docker-cli-image branch July 13, 2026 20:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Infrastructure]: Make Docker setup more complete

1 participant