diff --git a/.env.development.example b/.env.development.example index 9f594765d..6aa8f6419 100644 --- a/.env.development.example +++ b/.env.development.example @@ -30,6 +30,14 @@ DB_PORT=5432 # Enable Laravel Telescope for debugging TELESCOPE_ENABLED=false +# Enable Laravel Debugbar (disabled by default; set true when needed) +DEBUGBAR_ENABLED=false + +# Vite dev server. Defaults to localhost. For phone/LAN/Tailscale access, set to +# the host machine's reachable IP (e.g. VITE_HOST=100.75.155.70), then recreate vite. +VITE_HOST=localhost +VITE_PORT=5173 + # Enable Laravel Nightwatch monitoring NIGHTWATCH_ENABLED=false NIGHTWATCH_TOKEN= diff --git a/bootstrap/cache/.gitignore b/bootstrap/cache/.gitignore old mode 100644 new mode 100755 diff --git a/docker-compose-maxio.dev.yml b/docker-compose-maxio.dev.yml index 61037391b..610394964 100644 --- a/docker-compose-maxio.dev.yml +++ b/docker-compose-maxio.dev.yml @@ -96,6 +96,7 @@ services: container_name: coolify-vite working_dir: /var/www/html environment: + # Set VITE_HOST in .env to a browser-reachable IP/hostname for LAN/Tailscale access VITE_HOST: "${VITE_HOST:-localhost}" VITE_PORT: "${VITE_PORT:-5173}" ports: diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml index 8f84b5d60..7b753a037 100644 --- a/docker-compose.dev.yml +++ b/docker-compose.dev.yml @@ -96,6 +96,7 @@ services: container_name: coolify-vite working_dir: /var/www/html environment: + # Set VITE_HOST in .env to a browser-reachable IP/hostname for LAN/Tailscale access VITE_HOST: "${VITE_HOST:-localhost}" VITE_PORT: "${VITE_PORT:-5173}" ports: diff --git a/docker/development/Dockerfile b/docker/development/Dockerfile index a5e5a7a3c..28837fa41 100644 --- a/docker/development/Dockerfile +++ b/docker/development/Dockerfile @@ -98,5 +98,8 @@ RUN mkdir -p /etc/nginx/conf.d && \ COPY --from=minio-client /usr/bin/mc /usr/bin/mc RUN chmod +x /usr/bin/mc -# Switch to non-root user -USER www-data +# Stay as root for s6 init so bind-mounted workspaces work even when the host +# tree is root-owned (CI, Jean, rootful Docker). PHP-FPM/nginx still run as +# www-data via their service configs. Do NOT set USER www-data here — that +# makes init-setup (composer install) fail with "vendor could not be created". +USER root diff --git a/docker/development/etc/s6-overlay/s6-rc.d/init-setup/up b/docker/development/etc/s6-overlay/s6-rc.d/init-setup/up old mode 100644 new mode 100755 index 67e0f5c1a..c2bdb2294 --- a/docker/development/etc/s6-overlay/s6-rc.d/init-setup/up +++ b/docker/development/etc/s6-overlay/s6-rc.d/init-setup/up @@ -1,22 +1,6 @@ #!/command/execlineb -P -# Use with-contenv to ensure environment variables are available +# s6 oneshots are execline pipelines (shebang shell scripts are not run as sh). +# Delegate to a real shell script for readable setup logic. with-contenv -cd /var/www/html -foreground { - composer - install -} -foreground { - php - artisan - migrate - --step -} -foreground { - php - artisan - dev - --init -} - +/etc/s6-overlay/scripts/init-setup.sh diff --git a/docker/development/etc/s6-overlay/scripts/init-setup.sh b/docker/development/etc/s6-overlay/scripts/init-setup.sh new file mode 100755 index 000000000..e800ed6cd --- /dev/null +++ b/docker/development/etc/s6-overlay/scripts/init-setup.sh @@ -0,0 +1,42 @@ +#!/command/with-contenv sh +set -eu + +cd /var/www/html + +# When the project is bind-mounted, host ownership may be root:root while the +# app runs as www-data (UID 1000). Fix the minimum needed so composer/laravel +# can write, without a recursive chown of the whole tree. +prepare_bind_mount() { + mkdir -p \ + storage/framework/cache \ + storage/framework/sessions \ + storage/framework/views \ + storage/logs \ + bootstrap/cache + + if [ "$(id -u)" = "0" ]; then + # Top-level only: allows creating vendor/ when the mount is root-owned + chown www-data:www-data /var/www/html 2>/dev/null || true + chown -R www-data:www-data storage bootstrap/cache 2>/dev/null || true + git config --global --add safe.directory /var/www/html 2>/dev/null || true + fi +} + +prepare_bind_mount + +echo "👉 init-setup: composer install..." +# Run as root when needed so a root-owned bind mount cannot block vendor/ +# creation, then hand writable paths to www-data for PHP-FPM. +composer install --no-interaction + +echo "👉 init-setup: migrate..." +php artisan migrate --step --force + +echo "👉 init-setup: artisan dev --init..." +php artisan dev --init + +if [ "$(id -u)" = "0" ]; then + chown -R www-data:www-data vendor storage bootstrap/cache 2>/dev/null || true +fi + +echo "👉 init-setup: done" diff --git a/jean.json b/jean.json index 5cd8362d9..7e4bcc00b 100644 --- a/jean.json +++ b/jean.json @@ -1,8 +1,8 @@ { "scripts": { - "setup": "cp $JEAN_ROOT_PATH/.env . && mkdir -p .claude && cp $JEAN_ROOT_PATH/.claude/settings.local.json .claude/settings.local.json", + "setup": "cp $JEAN_ROOT_PATH/.env .", "teardown": null, - "run": "docker rm -f coolify coolify-minio-init coolify-realtime coolify-minio coolify-testing-host coolify-redis coolify-db coolify-mail coolify-vite; spin up; spin down" + "run": "docker rm -f coolify coolify-minio-init coolify-realtime coolify-minio coolify-testing-host coolify-redis coolify-db coolify-mail coolify-vite; docker compose -f docker-compose.yml -f docker-compose.dev.yml up; docker compose -f docker-compose.yml -f docker-compose.dev.yml down" }, "ports": [ { diff --git a/package.json b/package.json index 3cb3406c7..7b8d70d07 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "private": true, "type": "module", "scripts": { - "dev": "vite", + "dev": "vite --host", "build": "vite build" }, "devDependencies": { diff --git a/storage/app/.gitignore b/storage/app/.gitignore old mode 100644 new mode 100755 diff --git a/storage/app/public/.gitignore b/storage/app/public/.gitignore old mode 100644 new mode 100755 diff --git a/storage/debugbar/.gitignore b/storage/debugbar/.gitignore old mode 100644 new mode 100755 diff --git a/storage/framework/.gitignore b/storage/framework/.gitignore old mode 100644 new mode 100755 diff --git a/storage/framework/cache/.gitignore b/storage/framework/cache/.gitignore old mode 100644 new mode 100755 diff --git a/storage/framework/sessions/.gitignore b/storage/framework/sessions/.gitignore old mode 100644 new mode 100755 diff --git a/storage/framework/testing/.gitignore b/storage/framework/testing/.gitignore old mode 100644 new mode 100755 diff --git a/storage/framework/views/.gitignore b/storage/framework/views/.gitignore old mode 100644 new mode 100755 diff --git a/storage/logs/.gitignore b/storage/logs/.gitignore old mode 100644 new mode 100755 diff --git a/storage/pail/.gitignore b/storage/pail/.gitignore old mode 100644 new mode 100755 diff --git a/vite.config.js b/vite.config.js index 36069fb28..2e0ac170b 100644 --- a/vite.config.js +++ b/vite.config.js @@ -2,33 +2,30 @@ import { defineConfig, loadEnv } from "vite"; import laravel from "laravel-vite-plugin"; export default defineConfig(({ mode }) => { - const env = loadEnv(mode, process.cwd(), '') - const viteHost = env.VITE_HOST || null; - const vitePort = Number(env.VITE_PORT || 5173); + const env = loadEnv(mode, process.cwd(), ""); + // Prefer process.env so Docker Compose can override without writing .env. + // Set VITE_HOST to a browser-reachable hostname/IP when accessing the app + // from another device (LAN / Tailscale), e.g. VITE_HOST=100.75.155.70 + const viteHost = (process.env.VITE_HOST || env.VITE_HOST || "localhost").trim(); + const vitePort = Number(process.env.VITE_PORT || env.VITE_PORT || 5173); return { server: { watch: { - ignored: [ - "**/dev_*_data/**", - "**/storage/**", - ], + ignored: ["**/dev_*_data/**", "**/storage/**"], }, + // Listen on all interfaces so Docker / remote clients can reach the dev server host: "0.0.0.0", + port: vitePort, + strictPort: true, allowedHosts: true, - cors: { - origin: [ - /^https?:\/\/localhost(:\d+)?$/, - /^https?:\/\/127\.0\.0\.1(:\d+)?$/, - /^https?:\/\/\[::1\](:\d+)?$/, - ...(env.APP_URL ? [env.APP_URL] : []), - ...(viteHost ? [`http://${viteHost}:${vitePort}`, `https://${viteHost}:${vitePort}`] : []), - ], + // App (:8000) and Vite (:5173) are different origins; allow any host in dev + cors: true, + origin: `http://${viteHost}:${vitePort}`, + hmr: { + host: viteHost, + clientPort: vitePort, }, - origin: viteHost ? `http://${viteHost}:${vitePort}` : undefined, - hmr: viteHost - ? { host: viteHost, clientPort: vitePort } - : true, }, plugins: [ laravel({ @@ -36,5 +33,5 @@ export default defineConfig(({ mode }) => { refresh: true, }), ], - } + }; });