2025-12-27 17:30:07 +01:00
|
|
|
{ pkgs ? import <nixpkgs> {} }:
|
|
|
|
|
|
2026-08-19 12:38:25 +02:00
|
|
|
let
|
|
|
|
|
# Playwright's bundled Chromium is a prebuilt glibc binary. NixOS has no
|
|
|
|
|
# /usr/lib, so nix-ld (enabled system-wide) resolves its interpreter and
|
|
|
|
|
# NIX_LD_LIBRARY_PATH supplies the libraries below.
|
|
|
|
|
chromiumLibs = with pkgs; [
|
|
|
|
|
glib nss nspr atk at-spi2-atk at-spi2-core cups dbus expat
|
|
|
|
|
xorg.libxcb libxkbcommon alsa-lib libgbm mesa
|
|
|
|
|
xorg.libX11 xorg.libXext xorg.libXcomposite xorg.libXdamage
|
|
|
|
|
xorg.libXfixes xorg.libXrandr cairo pango systemd libdrm
|
|
|
|
|
];
|
|
|
|
|
in
|
|
|
|
|
|
2025-12-27 17:30:07 +01:00
|
|
|
pkgs.mkShell {
|
|
|
|
|
buildInputs = with pkgs; [
|
|
|
|
|
# PHP and tools
|
|
|
|
|
php83
|
|
|
|
|
php83Packages.composer
|
|
|
|
|
|
|
|
|
|
# Node.js and npm
|
|
|
|
|
nodejs_20
|
|
|
|
|
|
|
|
|
|
# Container tools
|
|
|
|
|
podman
|
|
|
|
|
podman-compose
|
|
|
|
|
|
|
|
|
|
# Database client (optional, for direct DB access)
|
2025-12-29 23:36:15 +01:00
|
|
|
mariadb.client
|
2025-12-27 17:30:07 +01:00
|
|
|
|
|
|
|
|
# Utilities
|
|
|
|
|
git
|
|
|
|
|
curl
|
|
|
|
|
gnumake
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
shellHook = ''
|
2025-12-27 21:18:09 +01:00
|
|
|
# Export user/group IDs for Docker permission matching
|
|
|
|
|
export USER_ID=$(id -u)
|
|
|
|
|
export GROUP_ID=$(id -g)
|
|
|
|
|
# Use keep-id for proper permission mapping in rootless podman
|
|
|
|
|
export PODMAN_USERNS=keep-id
|
2026-08-19 12:38:25 +02:00
|
|
|
|
|
|
|
|
export NIX_LD_LIBRARY_PATH="${pkgs.lib.makeLibraryPath chromiumLibs}:$NIX_LD_LIBRARY_PATH"
|
|
|
|
|
|
2026-08-19 00:13:46 +02:00
|
|
|
# Compose file location
|
|
|
|
|
COMPOSE_FILE="$PWD/docker/dev/docker-compose.yml"
|
|
|
|
|
|
|
|
|
|
# ===================
|
|
|
|
|
# ALIASES
|
|
|
|
|
# ===================
|
|
|
|
|
alias pc='podman-compose -f $COMPOSE_FILE'
|
|
|
|
|
|
2025-12-27 17:30:07 +01:00
|
|
|
# Define helper functions
|
2025-12-27 21:17:56 +01:00
|
|
|
dev-rebuild() {
|
2025-12-27 17:30:07 +01:00
|
|
|
echo "🔨 Rebuilding development environment..."
|
2026-08-19 00:13:46 +02:00
|
|
|
PODMAN_USERNS=keep-id podman-compose -f $COMPOSE_FILE down -v
|
|
|
|
|
PODMAN_USERNS=keep-id podman-compose -f $COMPOSE_FILE build --no-cache app
|
|
|
|
|
PODMAN_USERNS=keep-id podman-compose -f $COMPOSE_FILE up -d
|
2025-12-27 21:17:56 +01:00
|
|
|
echo "✅ Rebuild complete! Check logs with: dev-logs"
|
2025-12-27 17:30:07 +01:00
|
|
|
}
|
|
|
|
|
|
2025-12-27 21:17:56 +01:00
|
|
|
dev-rebuild-quick() {
|
2025-12-27 17:30:07 +01:00
|
|
|
echo "⚡ Quick rebuild (keeping volumes)..."
|
2026-08-19 00:13:46 +02:00
|
|
|
PODMAN_USERNS=keep-id podman-compose -f $COMPOSE_FILE down
|
|
|
|
|
PODMAN_USERNS=keep-id podman-compose -f $COMPOSE_FILE build app
|
|
|
|
|
PODMAN_USERNS=keep-id podman-compose -f $COMPOSE_FILE up -d
|
2025-12-27 17:30:07 +01:00
|
|
|
echo "✅ Quick rebuild complete!"
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-27 21:17:56 +01:00
|
|
|
dev-up() {
|
|
|
|
|
echo "🚀 Starting development environment..."
|
2026-08-19 00:13:46 +02:00
|
|
|
PODMAN_USERNS=keep-id podman-compose -f $COMPOSE_FILE up -d
|
2025-12-27 21:17:56 +01:00
|
|
|
echo "✅ Dev environment started!"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dev-down() {
|
|
|
|
|
echo "🛑 Stopping development environment..."
|
2026-08-19 00:13:46 +02:00
|
|
|
podman-compose -f $COMPOSE_FILE down
|
2025-12-27 21:17:56 +01:00
|
|
|
echo "✅ Dev environment stopped!"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dev-restart() {
|
|
|
|
|
echo "🔄 Restarting development environment..."
|
2026-08-19 00:13:46 +02:00
|
|
|
podman-compose -f $COMPOSE_FILE restart
|
2025-12-27 21:17:56 +01:00
|
|
|
echo "✅ Dev environment restarted!"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dev-logs() {
|
2026-08-19 00:13:46 +02:00
|
|
|
podman-compose -f $COMPOSE_FILE logs -f "$@"
|
2025-12-27 17:30:07 +01:00
|
|
|
}
|
|
|
|
|
|
2026-08-17 01:56:01 +02:00
|
|
|
dev-logs-db() {
|
2026-08-19 00:13:46 +02:00
|
|
|
podman-compose -f $COMPOSE_FILE logs -f db "$@"
|
2026-08-17 01:56:01 +02:00
|
|
|
}
|
|
|
|
|
|
2025-12-27 21:17:56 +01:00
|
|
|
dev-shell() {
|
2026-08-19 00:13:46 +02:00
|
|
|
podman-compose -f $COMPOSE_FILE exec app sh
|
2025-12-27 17:30:07 +01:00
|
|
|
}
|
|
|
|
|
|
2025-12-27 21:17:56 +01:00
|
|
|
dev-artisan() {
|
2026-08-19 00:13:46 +02:00
|
|
|
podman-compose -f $COMPOSE_FILE exec app php artisan "$@"
|
2025-12-27 17:30:07 +01:00
|
|
|
}
|
|
|
|
|
|
2026-08-17 01:56:01 +02:00
|
|
|
dev-test() {
|
2026-08-19 00:13:46 +02:00
|
|
|
podman-compose -f $COMPOSE_FILE exec -T app env $(grep -vE '^\s*(#|$)' .env.testing) php -d memory_limit=512M vendor/bin/phpunit "$@"
|
2026-08-17 01:56:01 +02:00
|
|
|
}
|
2026-08-19 02:09:42 +02:00
|
|
|
|
|
|
|
|
pest-browser() {
|
|
|
|
|
# Run Pest browser tests (Playwright) on the host. Pass --headed for a
|
|
|
|
|
# visible browser or --debug to pause on failure. Requires `npm run build`.
|
2026-08-20 22:05:39 +02:00
|
|
|
# A path argument replaces the default suite; flags alone keep it.
|
|
|
|
|
# Only existing paths count, so `--filter Logout` cannot silently
|
|
|
|
|
# unscope the run to the whole test directory.
|
|
|
|
|
local has_path=0
|
|
|
|
|
local skip_next=0
|
|
|
|
|
local arg
|
|
|
|
|
for arg in "$@"; do
|
|
|
|
|
if [ "$skip_next" -eq 1 ]; then
|
|
|
|
|
skip_next=0
|
|
|
|
|
continue
|
|
|
|
|
fi
|
|
|
|
|
case "$arg" in
|
|
|
|
|
--filter|--group|--exclude-group|--test-suffix)
|
|
|
|
|
skip_next=1
|
|
|
|
|
;;
|
|
|
|
|
-*) ;;
|
|
|
|
|
*)
|
|
|
|
|
if [ -e "$arg" ]; then
|
|
|
|
|
has_path=1
|
|
|
|
|
fi
|
|
|
|
|
;;
|
|
|
|
|
esac
|
|
|
|
|
done
|
|
|
|
|
|
|
|
|
|
if [ "$has_path" -eq 1 ]; then
|
|
|
|
|
vendor/bin/pest "$@"
|
|
|
|
|
else
|
|
|
|
|
vendor/bin/pest tests/Browser "$@"
|
|
|
|
|
fi
|
2026-08-19 02:09:42 +02:00
|
|
|
}
|
2026-08-17 01:56:01 +02:00
|
|
|
|
2025-12-27 21:18:09 +01:00
|
|
|
dev-fix-permissions() {
|
|
|
|
|
echo "🔧 Fixing file permissions..."
|
|
|
|
|
echo "This will require sudo to fix Docker-created files"
|
|
|
|
|
sudo chown -R $(id -u):$(id -g) storage/ bootstrap/cache/ vendor/ node_modules/ 2>/dev/null || true
|
|
|
|
|
echo "✅ Permissions fixed!"
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-27 20:55:04 +01:00
|
|
|
prod-build() {
|
|
|
|
|
local TAG="''${1:-latest}"
|
2026-08-16 17:29:19 +02:00
|
|
|
local REGISTRY="forge.lvl0.xyz"
|
|
|
|
|
local NAMESPACE="lvl0"
|
|
|
|
|
local IMAGE_NAME="dishplanner"
|
2026-01-06 20:59:16 +01:00
|
|
|
|
2025-12-27 20:55:04 +01:00
|
|
|
echo "🔨 Building production image..."
|
2026-01-09 01:09:48 +01:00
|
|
|
podman build --format docker -f Dockerfile -t ''${REGISTRY}/''${NAMESPACE}/''${IMAGE_NAME}:''${TAG} .
|
2025-12-27 20:55:04 +01:00
|
|
|
|
|
|
|
|
echo "✅ Build complete: ''${REGISTRY}/''${NAMESPACE}/''${IMAGE_NAME}:''${TAG}"
|
2026-08-16 17:29:19 +02:00
|
|
|
echo "Run 'prod-push' to push to Forgejo"
|
2025-12-27 20:55:04 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
prod-push() {
|
|
|
|
|
local TAG="''${1:-latest}"
|
2026-08-16 17:29:19 +02:00
|
|
|
local REGISTRY="forge.lvl0.xyz"
|
|
|
|
|
local NAMESPACE="lvl0"
|
|
|
|
|
local IMAGE_NAME="dishplanner"
|
2025-12-27 20:55:04 +01:00
|
|
|
|
2026-08-16 17:29:19 +02:00
|
|
|
echo "📤 Pushing to Forgejo registry..."
|
2025-12-27 20:55:04 +01:00
|
|
|
if podman push ''${REGISTRY}/''${NAMESPACE}/''${IMAGE_NAME}:''${TAG}; then
|
|
|
|
|
echo "✅ Image pushed to ''${REGISTRY}/''${NAMESPACE}/''${IMAGE_NAME}:''${TAG}"
|
|
|
|
|
else
|
|
|
|
|
echo "❌ Failed to push image. Did you run 'prod-build' first?"
|
|
|
|
|
echo " Also make sure you're logged in with 'prod-login'"
|
|
|
|
|
return 1
|
|
|
|
|
fi
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-06 20:59:16 +01:00
|
|
|
prod-build-nc() {
|
|
|
|
|
local TAG="''${1:-latest}"
|
2026-08-16 17:29:19 +02:00
|
|
|
local REGISTRY="forge.lvl0.xyz"
|
|
|
|
|
local NAMESPACE="lvl0"
|
|
|
|
|
local IMAGE_NAME="dishplanner"
|
2026-01-06 20:59:16 +01:00
|
|
|
|
|
|
|
|
echo "🔨 Building production image (no cache)..."
|
2026-01-09 01:09:48 +01:00
|
|
|
podman build --format docker --no-cache -f Dockerfile -t ''${REGISTRY}/''${NAMESPACE}/''${IMAGE_NAME}:''${TAG} .
|
2026-01-06 20:59:16 +01:00
|
|
|
|
|
|
|
|
echo "✅ Build complete: ''${REGISTRY}/''${NAMESPACE}/''${IMAGE_NAME}:''${TAG}"
|
2026-08-16 17:29:19 +02:00
|
|
|
echo "Run 'prod-push' to push to Forgejo"
|
2026-01-06 20:59:16 +01:00
|
|
|
}
|
|
|
|
|
|
2025-12-27 20:55:04 +01:00
|
|
|
prod-build-push() {
|
|
|
|
|
local TAG="''${1:-latest}"
|
|
|
|
|
prod-build "$TAG" && prod-push "$TAG"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
prod-login() {
|
2026-08-16 17:29:19 +02:00
|
|
|
echo "📝 Logging into Forgejo registry..."
|
|
|
|
|
podman login forge.lvl0.xyz
|
2025-12-27 20:55:04 +01:00
|
|
|
}
|
|
|
|
|
|
2025-12-27 17:30:07 +01:00
|
|
|
echo "🚀 Dish Planner Development Environment"
|
|
|
|
|
echo "======================================="
|
|
|
|
|
echo "PHP: $(php --version | head -n1)"
|
|
|
|
|
echo "Node: $(node --version)"
|
|
|
|
|
echo "Podman: $(podman --version)"
|
|
|
|
|
echo "Podman-compose: $(podman-compose --version 2>/dev/null || echo 'checking...')"
|
|
|
|
|
echo ""
|
2025-12-27 20:55:04 +01:00
|
|
|
echo "Development commands:"
|
2025-12-27 21:17:56 +01:00
|
|
|
echo " dev-up - Start development environment"
|
|
|
|
|
echo " dev-down - Stop development environment"
|
|
|
|
|
echo " dev-restart - Restart containers"
|
|
|
|
|
echo " dev-rebuild - Full rebuild (removes volumes)"
|
|
|
|
|
echo " dev-rebuild-quick - Quick rebuild (keeps volumes)"
|
|
|
|
|
echo " dev-logs [svc] - Follow logs (default: all)"
|
2026-08-17 01:56:01 +02:00
|
|
|
echo " dev-logs-db - Tail database logs"
|
2025-12-27 21:17:56 +01:00
|
|
|
echo " dev-shell - Enter app container"
|
|
|
|
|
echo " dev-artisan - Run artisan commands"
|
2026-08-17 01:56:01 +02:00
|
|
|
echo " dev-test [path] - Run PHPUnit suite (CI invocation)"
|
2026-08-19 02:09:42 +02:00
|
|
|
echo " pest-browser [--headed] - Run Pest browser tests (Playwright)"
|
2025-12-27 21:18:09 +01:00
|
|
|
echo " dev-fix-permissions - Fix Docker-created file permissions"
|
2025-12-27 17:30:07 +01:00
|
|
|
echo ""
|
2025-12-27 20:55:04 +01:00
|
|
|
echo "Production commands:"
|
2026-08-16 17:29:19 +02:00
|
|
|
echo " prod-login - Login to Forgejo registry"
|
2025-12-27 20:55:04 +01:00
|
|
|
echo " prod-build [tag] - Build production image (default: latest)"
|
2026-08-16 17:29:19 +02:00
|
|
|
echo " prod-push [tag] - Push image to Forgejo"
|
2025-12-27 20:55:04 +01:00
|
|
|
echo " prod-build-push - Build and push in one command"
|
2025-12-27 17:30:07 +01:00
|
|
|
echo ""
|
|
|
|
|
|
|
|
|
|
# Auto-start prompt
|
2026-08-19 00:13:46 +02:00
|
|
|
if [ -f "$COMPOSE_FILE" ]; then
|
2025-12-27 17:30:07 +01:00
|
|
|
read -p "Start development containers? (y/N) " -n 1 -r
|
|
|
|
|
echo
|
|
|
|
|
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
|
|
|
|
echo "Starting containers..."
|
2026-08-19 00:13:46 +02:00
|
|
|
podman-compose -f $COMPOSE_FILE up -d
|
2025-12-27 17:30:07 +01:00
|
|
|
|
|
|
|
|
# Wait a moment for containers to start
|
|
|
|
|
sleep 3
|
|
|
|
|
|
|
|
|
|
echo ""
|
|
|
|
|
echo "✅ Services should be available at:"
|
|
|
|
|
echo " App: http://localhost:8000"
|
|
|
|
|
echo " Vite: http://localhost:5173"
|
|
|
|
|
echo " Mailhog: http://localhost:8025"
|
|
|
|
|
echo " MariaDB: localhost:3306"
|
|
|
|
|
echo ""
|
2026-08-19 00:13:46 +02:00
|
|
|
echo "Run 'pc logs -f app' to follow logs"
|
2025-12-27 17:30:07 +01:00
|
|
|
fi
|
|
|
|
|
fi
|
|
|
|
|
'';
|
2026-08-19 00:13:46 +02:00
|
|
|
}
|