diff --git a/DOCKER.md b/DOCKER.md index 218cfe1ec..21538f1ba 100644 --- a/DOCKER.md +++ b/DOCKER.md @@ -83,14 +83,17 @@ Run `make` or `make help` to see all targets, grouped by section. | `make migrate` | Run pending migrations | | `make migrate-fresh`| Drop all tables and re-migrate (DATA LOSS) | | `make seed` | Run database seeders | -| `make cache-clear` | Clear config / route / view / app caches | -| `make optimize` | Cache config / routes / views + spatie/laravel-data | +| `make cache-clear` | Clear config / route / view / app caches (and stale `bootstrap/cache` files) | +| `make optimize` | Dev-safe: warm view cache + spatie/laravel-data | +| `make optimize-deploy` | Production: also caches config/routes (bakes absolute paths) | | `make queue-work` | Foreground queue worker | | `make queue-restart`| Signal queue workers to restart | | `make tmux-start` | Start the NNTmux tmux processing engine | | `make tmux-stop` | Stop the tmux processing engine | | `make tmux-attach` | Attach to the running tmux session | | `make horizon` | Show Horizon queue status | +| `make fix-permissions` | Chown project to host UID + register git `safe.directory` | +| `make fix-permissions` | Chown project to `sail` + register git safe.directory | ### Testing & Quality @@ -235,7 +238,12 @@ docker compose up -d | Problem | Solution | |---------------------------------|-----------------------------------------------------------------------| -| Permission errors on storage/ | `make root-shell` then `chown -R sail:sail storage bootstrap/cache` | +| Permission errors on storage/ | `make fix-permissions` (chowns project to your host UID) | +| `composer install` permission denied | `make fix-permissions`, then re-run `make composer-install` | +| `npm`/`ncu` EACCES on host (`package.json`) | `make fix-permissions` chowns to host UID, not container `sail` | +| `fatal: detected dubious ownership` (git) | `make fix-permissions` registers `safe.directory` in the container | +| Container `sail` UID ≠ host UID | Set `WWWUSER=$(id -u)` / `WWWGROUP=$(id -g)` in `.env`, then `make rebuild` | +| Host artisan/npm fails with `/var/www/html/...` paths | Stale `bootstrap/cache/config.php` from a container `config:cache`. Run `make cache-clear` and prefer `make optimize` (dev-safe) over `optimize-deploy` in development | | Port already in use | Change `APP_PORT`, `FORWARD_DB_PORT`, etc. in `.env` | | Containers won't start | `make logs` to inspect, or `make rebuild` to start fresh | | Stale images after upgrade | `make update` (pulls base images + rebuild + restart) | diff --git a/Makefile b/Makefile index c0f6b83a0..e124c4081 100644 --- a/Makefile +++ b/Makefile @@ -82,7 +82,7 @@ update: check-env pull ## Infra-only: pull base images, rebuild with --pull, res @$(SAIL) up -d --remove-orphans @echo "$(GREEN)✔ Infra updated.$(RESET)" .PHONY: upgrade -upgrade: update composer-install npm-build ## Full app upgrade: update + composer + npm + migrate + caches +upgrade: update fix-permissions composer-install npm-build ## Full app upgrade: update + perms + composer + npm + migrate + caches @if [ "$(MAINTENANCE)" = "1" ]; then $(SAIL) artisan down; fi @$(SAIL) artisan migrate --force @if [ "$(MAINTENANCE)" = "1" ]; then $(SAIL) artisan up; fi @@ -122,19 +122,26 @@ migrate-fresh: ## Drop all tables and re-run migrations (DATA LOSS!) seed: ## Run database seeders @$(SAIL) artisan db:seed --force .PHONY: cache-clear -cache-clear: ## Clear config / route / view / application caches +cache-clear: ## Clear config / route / view / application caches (and stale bootstrap/cache files) @$(SAIL) artisan config:clear @$(SAIL) artisan route:clear @$(SAIL) artisan view:clear @$(SAIL) artisan cache:clear + @rm -f bootstrap/cache/config.php bootstrap/cache/routes-v7.php bootstrap/cache/services.php bootstrap/cache/packages.php @echo "$(GREEN)✔ Caches cleared.$(RESET)" .PHONY: optimize -optimize: ## Cache config / routes / views and warm spatie/laravel-data +optimize: ## Dev-safe optimize: warm data structures + view cache only (no config/route cache) + @$(SAIL) artisan view:cache + @$(SAIL) artisan data:cache-structures + @echo "$(GREEN)✔ Optimized (dev-safe).$(RESET)" +.PHONY: optimize-deploy +optimize-deploy: ## Production optimize: cache config / routes / views + data structures (bakes absolute paths!) + @echo "$(YELLOW)⚠ This caches absolute paths from inside the container — only run on the deploy host.$(RESET)" @$(SAIL) artisan config:cache @$(SAIL) artisan route:cache @$(SAIL) artisan view:cache @$(SAIL) artisan data:cache-structures - @echo "$(GREEN)✔ Optimized.$(RESET)" + @echo "$(GREEN)✔ Optimized for deploy.$(RESET)" .PHONY: queue-work queue-work: ## Run a foreground queue worker (Ctrl-C to stop) @$(SAIL) artisan queue:work @@ -205,6 +212,26 @@ db: ## Open a MariaDB CLI session .PHONY: redis-cli redis-cli: ## Open a Redis CLI session @$(SAIL) redis +# Host UID/GID — used by fix-permissions so files stay writable from BOTH +# the host and the in-container sail user (whose UID should match WWWUSER). +HOST_UID ?= $(shell id -u) +HOST_GID ?= $(shell id -g) +.PHONY: fix-permissions +fix-permissions: ## Align UIDs: remap sail to host UID, chown project, register git safe.directory + @echo "$(YELLOW)→ Remapping container 'sail' user to UID $(HOST_UID) and chowning /var/www/html…$(RESET)" + @$(DOCKER_COMPOSE) exec -u root laravel.test usermod -u $(HOST_UID) -o sail >/dev/null 2>&1 || true + @$(DOCKER_COMPOSE) exec -u root laravel.test groupmod -g $(HOST_GID) -o sail >/dev/null 2>&1 || true + @$(DOCKER_COMPOSE) exec -u root laravel.test chown -R $(HOST_UID):$(HOST_GID) /var/www/html + @$(DOCKER_COMPOSE) exec -u root laravel.test git config --system --add safe.directory /var/www/html + @echo "$(GREEN)✔ Permissions fixed.$(RESET)" + @if [ "$(WWWUSER)" != "$(HOST_UID)" ] || [ -z "$(WWWUSER)" ]; then echo "$(YELLOW)⚠ WWWUSER ($(WWWUSER)) ≠ host UID ($(HOST_UID)). Set WWWUSER=$(HOST_UID) and WWWGROUP=$(HOST_GID) in .env, then run 'make rebuild' to align the container's sail user.$(RESET)"; fi +.PHONY: fix-perms +fix-perms: fix-permissions ## Alias for 'fix-permissions' + +.PHONY: git-safe-directory +git-safe-directory: ## Register /var/www/html as a git safe.directory inside the container + @$(DOCKER_COMPOSE) exec -u root laravel.test git config --system --add safe.directory /var/www/html >/dev/null 2>&1 || true + @$(DOCKER_COMPOSE) exec laravel.test git config --global --add safe.directory /var/www/html >/dev/null 2>&1 || true # ── Logs & Status ──────────────────────────────────────────── .PHONY: logs logs: ## Tail logs (usage: make logs [SERVICE=mariadb]) diff --git a/package.json b/package.json index 4bed16f6c..44de4b967 100644 --- a/package.json +++ b/package.json @@ -10,16 +10,16 @@ }, "devDependencies": { "@tailwindcss/forms": "^0.5.11", - "@tailwindcss/vite": "^4.2.2", - "axios": "1.14.0", + "@tailwindcss/vite": "^4.2.4", + "axios": "1.15.2", "lodash": "^4.18.1", - "npm-check-updates": "^20.0.0", - "prettier": "3.8.1", - "prettier-plugin-blade": "3.1.4", + "npm-check-updates": "^22.0.1", + "prettier": "3.8.3", + "prettier-plugin-blade": "3.1.6", "prettier-plugin-tailwindcss": "^0.7.2", - "tailwindcss": "^4.2.2", + "tailwindcss": "^4.2.4", "vite": "^8.0", - "vue": "^3.5.32" + "vue": "^3.5.33" }, "dependencies": { "@alpinejs/csp": "^3.15.11", @@ -30,8 +30,8 @@ "chart.js": "^4.5.1", "date-fns": "^4.1.0", "feather-icons": "^4.29.2", - "laravel-echo": "^2.3.3", - "laravel-vite-plugin": "^3.0", + "laravel-echo": "^2.3.4", + "laravel-vite-plugin": "^3.1", "nested-sort": "^5.2.0", "vuedraggable": "^4.1.0" }