feature - 6 - Structural fixes

This commit is contained in:
myrmidex 2025-12-27 21:18:09 +01:00
parent 6e5fb9cb36
commit 94abe140e1
29 changed files with 120 additions and 109 deletions

1
.gitignore vendored
View file

@ -22,3 +22,4 @@ yarn-error.log
/.nova /.nova
/.vscode /.vscode
/.zed /.zed
/.vite

View file

@ -0,0 +1,8 @@
{
"hash": "9e76e24f",
"configHash": "16a1459d",
"lockfileHash": "e3b0c442",
"browserHash": "8e8bb46e",
"optimized": {},
"chunks": {}
}

3
.vite/deps/package.json Normal file
View file

@ -0,0 +1,3 @@
{
"type": "module"
}

View file

@ -63,66 +63,54 @@ EOF
# Install Node development dependencies globally # Install Node development dependencies globally
RUN npm install -g nodemon RUN npm install -g nodemon
# Create startup script # Create startup script for development (runs as host user)
RUN cat > /start.sh <<'EOF' RUN cat > /start.sh <<'EOF'
#!/bin/sh #!/bin/sh
set -e set -e
# Ensure all required Laravel directories exist # Create .env file if it doesn't exist
mkdir -p /app/bootstrap/cache if [ ! -f ".env" ]; then
mkdir -p /app/storage/app/public echo "Creating .env file from .env.example..."
mkdir -p /app/storage/framework/cache/data cp .env.example .env
mkdir -p /app/storage/framework/sessions fi
mkdir -p /app/storage/framework/testing
mkdir -p /app/storage/framework/views
mkdir -p /app/storage/logs
# Set permissions - use www-data user # Install dependencies if volumes are empty
chown -R www-data:www-data /app/storage /app/bootstrap/cache
chmod -R 775 /app/storage /app/bootstrap/cache
# Create cache directories with proper permissions
mkdir -p /app/storage/framework/cache/data
chown -R www-data:www-data /app/storage/framework/cache
chmod -R 775 /app/storage/framework/cache
# Check if vendor exists in the volume
if [ ! -f "vendor/autoload.php" ]; then if [ ! -f "vendor/autoload.php" ]; then
echo "Installing composer dependencies..." echo "Installing composer dependencies..."
composer install composer install
else
echo "Composer dependencies found, skipping install..."
fi fi
# Check if node_modules exists in the volume # Handle node_modules with care - clean install if having issues
if [ ! -f "node_modules/.bin/vite" ]; then if [ ! -f "node_modules/.bin/vite" ]; then
echo "Installing npm dependencies..." echo "Installing npm dependencies..."
npm install # Clean any remnants first
rm -rf node_modules/.* 2>/dev/null || true
rm -rf /app/.npm 2>/dev/null || true
# Fresh install with cache in tmp to avoid permission issues
npm install --cache /tmp/.npm
else else
echo "Node modules found, skipping npm install..." echo "Node modules already installed, skipping npm install"
fi fi
# Run Laravel commands as www-data to avoid permission issues # Clear Laravel caches
su -s /bin/sh www-data -c "php artisan config:clear" || true php artisan config:clear || true
su -s /bin/sh www-data -c "php artisan cache:clear" || true php artisan cache:clear || true
su -s /bin/sh www-data -c "php artisan route:clear" || true
su -s /bin/sh www-data -c "php artisan view:clear" || true
# Run migrations if database is ready # Wait for database and run migrations
echo "Waiting for database..." echo "Waiting for database..."
sleep 5 sleep 5
su -s /bin/sh www-data -c "php artisan migrate --force" || echo "Migration failed or not needed" php artisan migrate --force || echo "Migration failed or not needed"
# Generate app key if not set # Generate app key if not set
if [ -z "$APP_KEY" ] || [ "$APP_KEY" = "base64:YOUR_KEY_HERE" ]; then if [ -z "$APP_KEY" ] || [ "$APP_KEY" = "base64:YOUR_KEY_HERE" ]; then
echo "Generating application key..." echo "Generating application key..."
su -s /bin/sh www-data -c "php artisan key:generate" php artisan key:generate
fi fi
# Start Vite dev server in background for hot reload # Start Vite dev server in background
npm run dev & npm run dev &
# Start FrankenPHP (runs as root in dev for simplicity) # Start FrankenPHP
exec frankenphp run --config /etc/caddy/Caddyfile exec frankenphp run --config /etc/caddy/Caddyfile
EOF EOF

View file

@ -31,6 +31,6 @@ public function login()
public function render() public function render()
{ {
return view('livewire.auth.login') return view('livewire.auth.login')
->layout('layouts.guest'); ->layout('components.layouts.guest');
} }
} }

View file

@ -2,7 +2,7 @@
namespace App\Livewire\Auth; namespace App\Livewire\Auth;
use App\Models\User; use App\Models\Planner;
use Livewire\Component; use Livewire\Component;
use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash; use Illuminate\Support\Facades\Hash;
@ -13,38 +13,25 @@ class Register extends Component
#[Rule('required|string|max:255')] #[Rule('required|string|max:255')]
public $name = ''; public $name = '';
#[Rule('required|email|unique:users,email')] #[Rule('required|email|unique:planners,email')]
public $email = ''; public $email = '';
#[Rule('required|min:8|confirmed')] #[Rule('required|min:8|confirmed')]
public $password = ''; public $password = '';
public $password_confirmation = ''; public $password_confirmation = '';
#[Rule('required|exists:planners,id')]
public $planner_id = '';
public function mount()
{
// Set default planner_id if only one exists
$planners = \App\Models\Planner::all();
if ($planners->count() === 1) {
$this->planner_id = $planners->first()->id;
}
}
public function register() public function register()
{ {
$this->validate(); $this->validate();
$user = User::create([ $planner = Planner::create([
'name' => $this->name, 'name' => $this->name,
'email' => $this->email, 'email' => $this->email,
'password' => Hash::make($this->password), 'password' => Hash::make($this->password),
'planner_id' => $this->planner_id,
]); ]);
Auth::login($user); Auth::login($planner);
session()->regenerate(); session()->regenerate();
return redirect()->route('dashboard'); return redirect()->route('dashboard');
@ -52,8 +39,7 @@ public function register()
public function render() public function render()
{ {
return view('livewire.auth.register', [ return view('livewire.auth.register')
'planners' => \App\Models\Planner::all() ->layout('components.layouts.guest');
])->layout('layouts.guest');
} }
} }

View file

@ -25,7 +25,8 @@
health: '/up', health: '/up',
) )
->withMiddleware(function (Middleware $middleware) { ->withMiddleware(function (Middleware $middleware) {
$middleware->append(ForceJsonResponse::class); // Apply ForceJsonResponse only to API routes
$middleware->api(ForceJsonResponse::class);
$middleware->append(StartSession::class); $middleware->append(StartSession::class);
$middleware->append(HandleCors::class); $middleware->append(HandleCors::class);
}) })

29
build-push.sh Executable file
View file

@ -0,0 +1,29 @@
#!/bin/bash
# Build and push production image to Codeberg
set -e
# Configuration
REGISTRY="codeberg.org"
NAMESPACE="lvl0"
IMAGE_NAME="dish-planner"
TAG="${1:-latest}"
echo "🔨 Building production image..."
podman build -f Dockerfile -t ${REGISTRY}/${NAMESPACE}/${IMAGE_NAME}:${TAG} .
echo "📤 Pushing to Codeberg registry..."
echo "Please ensure you're logged in to Codeberg:"
echo " podman login codeberg.org"
podman push ${REGISTRY}/${NAMESPACE}/${IMAGE_NAME}:${TAG}
echo "✅ Done! Image pushed to ${REGISTRY}/${NAMESPACE}/${IMAGE_NAME}:${TAG}"
echo ""
echo "To deploy in production:"
echo "1. Copy docker-compose.prod.yml to your server"
echo "2. Set required environment variables:"
echo " - APP_KEY (generate with: openssl rand -base64 32)"
echo " - APP_URL"
echo " - DB_DATABASE, DB_USERNAME, DB_PASSWORD, DB_ROOT_PASSWORD"
echo "3. Run: docker-compose -f docker-compose.prod.yml up -d"

3
build_and_push.sh Executable file
View file

@ -0,0 +1,3 @@
#!/bin/bash
docker build -t 192.168.178.152:50114/dishplanner-backend .
docker push 192.168.178.152:50114/dishplanner-backend

View file

@ -1,25 +0,0 @@
services:
backend:
volumes:
- '.:/var/www/html:Z'
mysql:
image: 'docker.io/library/mysql:8.0'
environment:
MYSQL_USER: '${DB_USERNAME}'
MYSQL_PASSWORD: '${DB_PASSWORD}'
volumes:
- 'sail-mysql:/var/lib/mysql:Z'
frontend:
image: 'docker.io/library/node:22-alpine'
working_dir: /app
command: sh -c "npm install && npm run dev -- --host"
volumes:
- '../frontend:/app:Z'
ports:
- '5173:5173'
networks:
- sail
depends_on:
- backend

View file

@ -8,6 +8,8 @@ services:
dockerfile: Dockerfile.dev dockerfile: Dockerfile.dev
container_name: dishplanner_app container_name: dishplanner_app
restart: unless-stopped restart: unless-stopped
# Remove user directive to run as root in container
# The container will handle permissions internally
ports: ports:
- "8000:8000" # Laravel app - "8000:8000" # Laravel app
- "5173:5173" # Vite dev server - "5173:5173" # Vite dev server
@ -38,13 +40,11 @@ services:
# Vite # Vite
VITE_HOST: "0.0.0.0" VITE_HOST: "0.0.0.0"
volumes: volumes:
# Mount entire project for hot reload # Mount entire project for hot reload with SELinux context
- .:/app - .:/app:Z
# Persist vendor and node_modules for performance # Named volumes for performance and permission isolation
- app_vendor:/app/vendor - app_vendor:/app/vendor
- app_node_modules:/app/node_modules - app_node_modules:/app/node_modules
# Persist storage
- app_storage:/app/storage
depends_on: depends_on:
- db - db
networks: networks:
@ -101,5 +101,4 @@ networks:
volumes: volumes:
db_data: db_data:
app_vendor: app_vendor:
app_node_modules: app_node_modules:
app_storage:

0
public/.htaccess Normal file → Executable file
View file

0
public/favicon.ico Normal file → Executable file
View file

0
public/index.php Normal file → Executable file
View file

0
public/robots.txt Normal file → Executable file
View file

View file

@ -23,20 +23,6 @@ class="w-full p-2 mb-4 border rounded bg-gray-600 border-secondary text-gray-100
@error('email') <span class="text-danger text-xs block -mt-2 mb-2">{{ $message }}</span> @enderror @error('email') <span class="text-danger text-xs block -mt-2 mb-2">{{ $message }}</span> @enderror
</div> </div>
@if($planners->count() > 1)
<div>
<label for="planner_id" class="block text-sm font-medium mb-2">Planner</label>
<select wire:model="planner_id"
id="planner_id"
class="w-full p-2 mb-4 border rounded bg-gray-600 border-secondary text-gray-100 focus:bg-gray-900 focus:outline-none focus:border-accent-blue">
<option value="">Select a planner</option>
@foreach($planners as $planner)
<option value="{{ $planner->id }}">{{ $planner->name }}</option>
@endforeach
</select>
@error('planner_id') <span class="text-danger text-xs block -mt-2 mb-2">{{ $message }}</span> @enderror
</div>
@endif
<div> <div>
<label for="password" class="block text-sm font-medium mb-2">Password</label> <label for="password" class="block text-sm font-medium mb-2">Password</label>

View file

@ -23,26 +23,32 @@ pkgs.mkShell {
]; ];
shellHook = '' shellHook = ''
# 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
# Define helper functions # Define helper functions
dev-rebuild() { dev-rebuild() {
echo "🔨 Rebuilding development environment..." echo "🔨 Rebuilding development environment..."
podman-compose down -v PODMAN_USERNS=keep-id podman-compose down -v
podman-compose build --no-cache app PODMAN_USERNS=keep-id podman-compose build --no-cache app
podman-compose up -d PODMAN_USERNS=keep-id podman-compose up -d
echo " Rebuild complete! Check logs with: dev-logs" echo " Rebuild complete! Check logs with: dev-logs"
} }
dev-rebuild-quick() { dev-rebuild-quick() {
echo " Quick rebuild (keeping volumes)..." echo " Quick rebuild (keeping volumes)..."
podman-compose down PODMAN_USERNS=keep-id podman-compose down
podman-compose build app PODMAN_USERNS=keep-id podman-compose build app
podman-compose up -d PODMAN_USERNS=keep-id podman-compose up -d
echo " Quick rebuild complete!" echo " Quick rebuild complete!"
} }
dev-up() { dev-up() {
echo "🚀 Starting development environment..." echo "🚀 Starting development environment..."
podman-compose up -d PODMAN_USERNS=keep-id podman-compose up -d
echo " Dev environment started!" echo " Dev environment started!"
} }
@ -70,6 +76,13 @@ pkgs.mkShell {
podman-compose exec app php artisan "$@" podman-compose exec app php artisan "$@"
} }
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!"
}
prod-build() { prod-build() {
local TAG="''${1:-latest}" local TAG="''${1:-latest}"
local REGISTRY="codeberg.org" local REGISTRY="codeberg.org"
@ -125,6 +138,7 @@ pkgs.mkShell {
echo " dev-logs [svc] - Follow logs (default: all)" echo " dev-logs [svc] - Follow logs (default: all)"
echo " dev-shell - Enter app container" echo " dev-shell - Enter app container"
echo " dev-artisan - Run artisan commands" echo " dev-artisan - Run artisan commands"
echo " dev-fix-permissions - Fix Docker-created file permissions"
echo "" echo ""
echo "Production commands:" echo "Production commands:"
echo " prod-login - Login to Codeberg registry" echo " prod-login - Login to Codeberg registry"

0
storage/app/.gitignore vendored Normal file → Executable file
View file

0
storage/app/private/.gitignore vendored Normal file → Executable file
View file

0
storage/app/public/.gitignore vendored Normal file → Executable file
View file

0
storage/framework/.gitignore vendored Normal file → Executable file
View file

0
storage/framework/cache/.gitignore vendored Normal file → Executable file
View file

0
storage/framework/cache/data/.gitignore vendored Normal file → Executable file
View file

0
storage/framework/sessions/.gitignore vendored Normal file → Executable file
View file

0
storage/framework/testing/.gitignore vendored Normal file → Executable file
View file

0
storage/framework/views/.gitignore vendored Normal file → Executable file
View file

18
update.sh Executable file
View file

@ -0,0 +1,18 @@
#!/bin/bash
set -e
echo "🔄 Pulling latest backend changes..."
git pull origin main
echo "📦 Installing PHP dependencies..."
composer install --no-interaction --prefer-dist --optimize-autoloader
echo "🗄️ Running migrations..."
php artisan migrate --force
echo "🧹 Clearing and caching config..."
php artisan config:cache
php artisan route:cache
php artisan view:cache
echo "✅ Backend update complete!"