Replaces the bare-metal `composer run dev` workflow with a fully containerized 9-service stack orchestrated by docker compose. Single command brings up the full app — three subdomains (marketing / account / admin) reachable via Traefik with TLS, MariaDB + Valkey + Mailpit + Vite HMR + Horizon + scheduler all wired in. Components: - docker-compose.yml: traefik, app (php-fpm), web (nginx), mariadb, valkey, mailpit, vite, horizon, scheduler. - docker/: Dockerfiles, nginx config, entrypoint scripts. - Makefile: convenience targets (up / down / logs / shell / migrate / seed / test / pint / etc). - .env.docker.example: template for Docker-stack environment vars (separate from website/.env so bare-metal devs aren't disrupted). - website/vite.config.ts: server.host / origin / hmr / cors hooks driven by VITE_HOST / VITE_ORIGIN / VITE_HMR_HOST so the same config serves both bare-metal and Docker. - website/bootstrap/app.php: redirectGuestsTo() now uses request()->getScheme() so http: dev hosts don't get force-https redirects. - composer.json: drops laravel/sail (replaced by this stack). - docs/superpowers/specs/2026-04-25-docker-compose-dev-environment-design.md: full design spec. Bare-metal `composer run dev` workflow stays usable for anyone who prefers it — Docker stack reads .env.docker, doesn't fight website/.env. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
143 lines
6.4 KiB
Markdown
143 lines
6.4 KiB
Markdown
# EZSCALE — Docker Compose Dev Environment
|
|
|
|
Multi-service development stack for the EZSCALE Laravel app. Replaces the bare-metal `composer run dev` workflow with a fully-containerized environment that mirrors the production topology (nginx + PHP-FPM + MariaDB + Valkey + Horizon).
|
|
|
|
## Prerequisites
|
|
|
|
- **Docker Engine 24+** with **Compose V2** (`docker compose`, not `docker-compose`)
|
|
- **WSL2 with files cloned under `/home/$USER/`** (NOT `/mnt/c/...` — bind-mount performance is unusable on the Windows-mounted filesystem)
|
|
- A modern browser (Chrome, Firefox, Safari) — `*.docker.localhost` resolution requires no `/etc/hosts` edits
|
|
|
|
## First-time setup
|
|
|
|
```bash
|
|
make init
|
|
```
|
|
|
|
That single command:
|
|
1. Copies `.env.docker.example` → `.env.docker`
|
|
2. Builds all custom images (PHP-FPM, nginx, vite)
|
|
3. Pulls third-party images (Traefik, MariaDB, Valkey, Mailpit)
|
|
4. Boots MariaDB and Valkey, waits for them to be healthy
|
|
5. Runs `composer install` and `npm install`
|
|
6. Brings up the rest of the stack
|
|
|
|
When `make init` finishes, you should be able to open:
|
|
|
|
- **https://ezscale.docker.localhost** — marketing site
|
|
- **https://account.ezscale.docker.localhost** — customer dashboard
|
|
- **https://admin.ezscale.docker.localhost** — admin panel
|
|
- **https://account.ezscale.docker.localhost/horizon** — Horizon dashboard
|
|
- **https://mail.ezscale.docker.localhost** — Mailpit UI (catches all outgoing email)
|
|
- **https://vite.ezscale.docker.localhost** — Vite dev server (for HMR)
|
|
- **http://localhost:8080** — Traefik dashboard (insecure, dev-only)
|
|
|
|
The first time you visit any of these, your browser will warn about a self-signed cert. Accept once — Traefik issues a wildcard cert covering all subdomains.
|
|
|
|
## Daily commands
|
|
|
|
```bash
|
|
make up # bring stack up
|
|
make down # stop (volumes preserved)
|
|
make logs # tail all logs
|
|
make logs SVC=horizon # tail one service
|
|
make sh # bash inside app container
|
|
make artisan ARGS="migrate" # any artisan command
|
|
make composer ARGS="require foo/bar"
|
|
make npm ARGS="install foo"
|
|
make test # php artisan test --compact
|
|
make pint # format dirty PHP
|
|
make fresh # migrate:fresh --seed
|
|
make destroy # nuclear: stop + wipe volumes
|
|
```
|
|
|
|
`make help` prints the full list.
|
|
|
|
## Architecture
|
|
|
|
| Service | Image | Role |
|
|
|---------|-------|------|
|
|
| `traefik` | `traefik:v3.6` | Edge proxy + TLS termination + routing |
|
|
| `app` | custom (PHP 8.3-FPM Debian) | Application container |
|
|
| `web` | `nginx:1.30-alpine` | Serves `public/`, proxies PHP |
|
|
| `vite` | custom (Node 24 Alpine) | HMR dev server |
|
|
| `horizon` | same as `app` | Queue worker supervisor |
|
|
| `scheduler` | same as `app` | `schedule:work` runner |
|
|
| `mariadb` | `mariadb:12` | Primary database |
|
|
| `valkey` | `valkey/valkey:9-alpine` | Sessions/cache/queues |
|
|
| `mailpit` | `axllent/mailpit:v1.29` | SMTP catcher |
|
|
|
|
Traefik routes the three Laravel subdomains (marketing/account/admin) to the same nginx container. Laravel's `Route::domain()` in `bootstrap/app.php` handles per-subdomain dispatch internally.
|
|
|
|
## Environment
|
|
|
|
The stack reads `.env.docker` at the repo root — separate from `website/.env`. This keeps the Docker workflow from fighting any bare-metal `composer run dev` setup you might still want to use.
|
|
|
|
Critical Docker-specific values:
|
|
|
|
```
|
|
DB_HOST=mariadb
|
|
REDIS_HOST=valkey
|
|
MAIL_HOST=mailpit
|
|
APP_URL=https://ezscale.docker.localhost
|
|
```
|
|
|
|
Third-party API keys (Stripe, PayPal, VirtFusion, etc.) need to be added to your `.env.docker` if you want to test those integrations.
|
|
|
|
## Volumes
|
|
|
|
Persisted across `make down` (lost only on `make destroy`):
|
|
|
|
- `mariadb_data` — MySQL data
|
|
- `valkey_data` — Valkey AOF persistence
|
|
- `mailpit_data` — captured email
|
|
- `traefik_certs` — self-signed cert cache
|
|
|
|
The Laravel source (`./website`) is bind-mounted live — your edits show up immediately. `vendor/` and `node_modules/` are visible on the host for IDE autocomplete.
|
|
|
|
## TLS
|
|
|
|
Traefik auto-generates a single self-signed wildcard cert for `*.ezscale.docker.localhost` on first boot. The cert lives in the `traefik_certs` volume.
|
|
|
|
If you want a green-padlock experience instead of accepting the warning once per browser:
|
|
|
|
```bash
|
|
brew install mkcert # or apt/winget equivalent
|
|
mkcert -install
|
|
mkcert -cert-file docker/traefik/certs/cert.pem \
|
|
-key-file docker/traefik/certs/key.pem \
|
|
"ezscale.docker.localhost" "*.ezscale.docker.localhost"
|
|
```
|
|
|
|
Then update `docker/traefik/dynamic.yml` to point `certificates:` at those files. Currently configured for self-signed; mkcert is left as a future enhancement.
|
|
|
|
## Common gotchas
|
|
|
|
**Port 80 or 443 already in use.**
|
|
Edit `docker-compose.yml`'s `traefik` service and remap to e.g. `8000:80`, `8443:443`. Then access the stack at `https://ezscale.docker.localhost:8443`.
|
|
|
|
**`make init` hangs on "waiting for mariadb".**
|
|
First MariaDB boot creates the system tablespace and can take 20-30s. The healthcheck has a 30s `start_period` to accommodate this. If it really stalls, `make logs SVC=mariadb` to see why.
|
|
|
|
**Permission errors on `storage/logs/laravel.log`.**
|
|
The PHP container's UID matches your host UID (1000) by default. If your host UID differs, rebuild with `UID=$(id -u) GID=$(id -g) make build`.
|
|
|
|
**Horizon dashboard 403s.**
|
|
Horizon's gate is in `App\Providers\HorizonServiceProvider::gate()`. In dev all admin users have access; you need to log in with an admin role first.
|
|
|
|
**Vite assets don't load.**
|
|
Check `make logs SVC=vite`. The Laravel Vite plugin auto-injects the dev URL — if it can't reach `https://vite.ezscale.docker.localhost`, assets fall back to the manifest. Make sure that hostname is reachable in your browser.
|
|
|
|
**Composer/npm install slow.**
|
|
First-time `composer install` takes 1-2 min. After that the `vendor/` dir is cached on disk. Same for `node_modules`.
|
|
|
|
## Co-existing with bare-metal dev
|
|
|
|
This stack does NOT delete or modify `website/.env`. If you previously used `cd website && composer run dev`, that still works — it reads `website/.env` and connects to whatever local PHP/MySQL/Redis you had.
|
|
|
|
Pick one or the other for any given session. Don't run both simultaneously (they'd fight over ports and sessions).
|
|
|
|
## Spec
|
|
|
|
Full design rationale in [`docs/superpowers/specs/2026-04-25-docker-compose-dev-environment-design.md`](../docs/superpowers/specs/2026-04-25-docker-compose-dev-environment-design.md).
|