From 8a9719ab9f6f139b6beba70472be6437b723f4c5 Mon Sep 17 00:00:00 2001 From: Tilman Behrend Date: Mon, 22 Sep 2025 13:21:36 +0200 Subject: [PATCH] add deployment for shared hosting without db --- .gitignore | 1 + deploy.sh | 538 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 539 insertions(+) create mode 100755 deploy.sh diff --git a/.gitignore b/.gitignore index f628679..df866ed 100644 --- a/.gitignore +++ b/.gitignore @@ -22,3 +22,4 @@ pnpm-debug.log* *.sln *.sw? /.history +/deployment diff --git a/deploy.sh b/deploy.sh new file mode 100755 index 0000000..a0faa97 --- /dev/null +++ b/deploy.sh @@ -0,0 +1,538 @@ +#!/bin/bash +# filepath: /Users/tbehrend/Repositories/thatsme/deploy-shared-no-db.sh + +echo "πŸš€ Creating deployment packages for 'That's Me' development structure..." + +# Clean up previous deployment +rm -rf development +mkdir -p development/{frontend,backend} + +echo "πŸ“¦ Building frontend..." +cd frontend +npm install +quasar build +cd .. + +echo "πŸ”§ Preparing backend..." +cd backend +composer install --optimize-autoloader --no-dev --no-interaction + +if [ -f "package.json" ]; then + npm install + NODE_ENV=production npm run build +fi +cd .. + +echo "πŸ“‚ Creating FRONTEND deployment structure..." + +# Frontend deployment - complete Quasar SPA +cp -r frontend/dist/spa/* development/frontend/ +cp -r frontend/public/images development/frontend/ +cp -r frontend/public/videos development/frontend/ +if [ -d "frontend/public/audio" ]; then + cp -r frontend/public/audio development/frontend/ +fi + +# Create frontend config for development deployment +cat > development/frontend/config.js << 'EOF' +// Frontend configuration for development deployment +window.APP_CONFIG = { + API_BASE_URL: '/api', + APP_URL: window.location.origin, + environment: 'development', + database: false +}; +EOF + +# Update frontend index.html to include config +sed -i.bak 's|| \n |' development/frontend/index.html + +# Create frontend .htaccess for SPA routing +cat > development/frontend/.htaccess << 'EOF' + + + Options -MultiViews -Indexes + + + RewriteEngine On + + # Handle client-side routing for Vue SPA + RewriteCond %{REQUEST_FILENAME} !-f + RewriteCond %{REQUEST_FILENAME} !-d + RewriteRule . /index.html [L] + + +# Cache static assets + + ExpiresActive on + ExpiresByType text/css "access plus 1 year" + ExpiresByType application/javascript "access plus 1 year" + ExpiresByType image/png "access plus 1 year" + ExpiresByType image/jpg "access plus 1 year" + ExpiresByType image/jpeg "access plus 1 year" + ExpiresByType image/gif "access plus 1 year" + ExpiresByType image/webp "access plus 1 year" + ExpiresByType video/mp4 "access plus 1 month" + + +# Security headers + + Header always set X-Content-Type-Options nosniff + Header always set X-Frame-Options SAMEORIGIN + Header always set X-XSS-Protection "1; mode=block" + +EOF + +echo "πŸ“‚ Creating BACKEND deployment structure..." + +# Backend deployment - Laravel application +mkdir -p development/backend/{app,bootstrap,config,database,resources,routes,storage,vendor,public} + +# Copy Laravel core files +cp -r backend/app development/backend/ +cp -r backend/bootstrap development/backend/ +cp -r backend/config development/backend/ +cp -r backend/database development/backend/ +cp -r backend/resources development/backend/ +cp -r backend/routes development/backend/ +cp -r backend/storage development/backend/ +cp -r backend/vendor development/backend/ + +# Copy backend root files +cp backend/artisan development/backend/ +cp backend/composer.json development/backend/ +cp backend/composer.lock development/backend/ +if [ -f "backend/vite.config.js" ]; then + cp backend/vite.config.js development/backend/ +fi + +# Copy built assets to public +if [ -d "backend/public/build" ]; then + cp -r backend/public/build development/backend/public/ +fi + +# Copy other public assets +if [ -d "backend/public" ]; then + rsync -av --exclude='build' backend/public/ development/backend/public/ +fi + +# Create backend index.php for development structure +cat > development/backend/public/index.php << 'EOF' +make(Kernel::class); + +$response = $kernel->handle( + $request = Request::capture() +); + +$response->send(); + +$kernel->terminate($request, $response); +EOF + +# Create backend .htaccess +cat > development/backend/public/.htaccess << 'EOF' + + + Options -MultiViews -Indexes + + + RewriteEngine On + + # Handle Authorization Header + RewriteCond %{HTTP:Authorization} . + RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}] + + # Redirect Trailing Slashes If Not A Folder + RewriteCond %{REQUEST_FILENAME} !-d + RewriteCond %{REQUEST_URI} (.+)/$ + RewriteRule ^ %1 [L,R=301] + + # Send Requests To Front Controller + RewriteCond %{REQUEST_FILENAME} !-d + RewriteCond %{REQUEST_FILENAME} !-f + RewriteRule ^ index.php [L] + + +# Security headers + + Header always set X-Content-Type-Options nosniff + Header always set X-Frame-Options DENY + Header always set X-XSS-Protection "1; mode=block" + + # CORS for development + Header always set Access-Control-Allow-Origin "*" + Header always set Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS" + Header always set Access-Control-Allow-Headers "Content-Type, Authorization, X-Requested-With" + +EOF + +# Create API routes for backend (database-free) +cat > development/backend/routes/web.php << 'EOF' +group(function () { + Route::middleware(['web'])->group(function () { + + Route::get('/health', function () { + return response()->json([ + 'status' => 'ok', + 'app' => 'That\'s Me Backend API', + 'version' => '1.0.0', + 'mode' => 'development-no-database', + 'timestamp' => now()->toISOString() + ]); + }); + + // Mock LifeWave data for anime.js visualizations + Route::get('/life-events', function () { + return response()->json([ + 'events' => [ + [ + 'id' => 1, + 'title' => 'Schulanfang', + 'value' => 0.8, + 'x' => 0.1, + 'imageUrl' => '/images/thumbs/aaron-huber-RLs8LZcONCA-unsplash.jpg', + 'date' => '2010-09-01', + 'description' => 'Mein erster Schultag war aufregend und voller neuer Erfahrungen.', + 'animationDelay' => 100 + ], + [ + 'id' => 2, + 'title' => 'Erster Job', + 'value' => 0.9, + 'x' => 0.3, + 'imageUrl' => '/images/thumbs/andrew-bui-z7rzbFHXym0-unsplash.jpg', + 'date' => '2020-03-15', + 'description' => 'Der Beginn meiner beruflichen Laufbahn in einem tollen Team.', + 'animationDelay' => 200 + ], + [ + 'id' => 3, + 'title' => 'Umzug nach MΓΌnchen', + 'value' => 0.6, + 'x' => 0.5, + 'imageUrl' => '/images/thumbs/becca-tapert--A_Sx8GrRWg-unsplash.jpg', + 'date' => '2022-06-20', + 'description' => 'Ein großer Schritt in eine neue Stadt und neue MΓΆglichkeiten.', + 'animationDelay' => 300 + ], + [ + 'id' => 4, + 'title' => 'Hochzeit', + 'value' => 1.0, + 'x' => 0.7, + 'imageUrl' => '/images/thumbs/fuu-j-r2nJPbEYuSQ-unsplash.jpg', + 'date' => '2023-08-12', + 'description' => 'Der schΓΆnste Tag meines Lebens mit der Person, die ich liebe.', + 'isFavorite' => true, + 'animationDelay' => 400 + ], + [ + 'id' => 5, + 'title' => 'Neues Projekt', + 'value' => 0.85, + 'x' => 0.9, + 'imageUrl' => '/images/thumbs/ian-dooley-hpTH5b6mo2s-unsplash.jpg', + 'date' => '2024-01-10', + 'description' => 'Start eines spannenden neuen Projekts mit großem Potenzial.', + 'isFavorite' => true, + 'animationDelay' => 500 + ] + ], + 'waveConfig' => [ + 'amplitude' => 0.3, + 'frequency' => 2, + 'animationDuration' => 2000, + 'easingFunction' => 'easeInOutQuad' + ] + ]); + }); + + // Mock entry detail for LifeWave interaction + Route::get('/entries/{id}', function ($id) { + $events = [ + 1 => [ + 'id' => 1, + 'title' => 'Schulanfang', + 'subtitle' => 'Ein wichtiger Meilenstein', + 'date' => '2010-09-01', + 'time' => '08:00', + 'location' => 'Grundschule am Park', + 'level' => 2, + 'keyImage' => '/images/thumbs/aaron-huber-RLs8LZcONCA-unsplash.jpg', + 'description' => 'Mein erster Schultag war aufregend und voller neuer Erfahrungen. Die SchultΓΌte war schwer und ich war gleichzeitig nervΓΆs und neugierig.', + 'additionalImages' => [ + ['url' => '/images/thumbs/andrew-bui-z7rzbFHXym0-unsplash.jpg', 'caption' => 'Vorbereitung am Morgen'], + ['url' => '/images/thumbs/becca-tapert--A_Sx8GrRWg-unsplash.jpg', 'caption' => 'Mit der Familie'] + ], + 'audioRecordings' => [ + ['name' => 'Erinnerungen', 'url' => '/audio/sample.mp3'] + ], + 'videoRecordings' => [ + ['name' => 'Einschulungsfeier', 'url' => '/videos/3191901-uhd_3840_2160_25fps.mp4'] + ], + 'relatedPersons' => [ + ['id' => 1, 'name' => 'Mama', 'relation' => 'Mutter', 'avatar' => null], + ['id' => 2, 'name' => 'Papa', 'relation' => 'Vater', 'avatar' => null] + ], + 'categories' => [ + ['id' => 1, 'name' => 'Bildung', 'icon' => 'school'], + ['id' => 2, 'name' => 'Familie', 'icon' => 'family_restroom'] + ], + 'tags' => [ + ['id' => 1, 'name' => 'Aufregend', 'icon' => 'emoji_emotions'], + ['id' => 2, 'name' => 'Neuanfang', 'icon' => 'new_releases'] + ] + ] + ]; + + $event = $events[$id] ?? [ + 'id' => (int)$id, + 'title' => 'Sample Entry ' . $id, + 'subtitle' => 'Ein wichtiger Meilenstein', + 'date' => '2023-08-12', + 'time' => '14:30', + 'location' => 'MΓΌnchen, Deutschland', + 'level' => 2, + 'keyImage' => '/images/familie2.png', + 'description' => 'Eine detaillierte Beschreibung dieses wichtigen Lebensereignisses.' + ]; + + return response()->json($event); + }); + }); +}); + +// Simple API info page +Route::get('/', function () { + return response()->json([ + 'app' => 'That\'s Me Backend API (Development)', + 'frontend_path' => '../frontend/', + 'api_endpoints' => [ + 'health' => '/api/health', + 'life_events' => '/api/life-events', + 'entry_detail' => '/api/entries/{id}' + ], + 'note' => 'Database-free development mode with mock LifeWave data' + ]); +}); +EOF + +# Create backend environment file for development +cat > development/backend/.env.production << 'EOF' +APP_NAME="That's Me Backend (Development)" +APP_ENV=production +APP_KEY= +APP_DEBUG=false +APP_URL=http://localhost + +LOG_CHANNEL=single +LOG_DEPRECATIONS_CHANNEL=null +LOG_LEVEL=error + +# NO DATABASE CONFIGURATION +# Database is disabled for this development deployment + +# Cache Configuration (file-based, no database) +BROADCAST_DRIVER=log +CACHE_DRIVER=file +FILESYSTEM_DISK=local +QUEUE_CONNECTION=sync +SESSION_DRIVER=file +SESSION_LIFETIME=120 + +# Mail Configuration (optional) +MAIL_MAILER=log +EOF + +# Create root .htaccess for combined deployment +cat > development/.htaccess << 'EOF' + + + Options -MultiViews -Indexes + + + RewriteEngine On + + # API routes to backend + RewriteCond %{REQUEST_URI} ^/api/ + RewriteRule ^api/(.*)$ /backend/public/index.php [L,QSA] + + # Backend admin routes + RewriteCond %{REQUEST_URI} ^/admin/ + RewriteRule ^admin/(.*)$ /backend/public/index.php [L,QSA] + + # Frontend SPA (default) + RewriteCond %{REQUEST_FILENAME} !-f + RewriteCond %{REQUEST_FILENAME} !-d + RewriteCond %{REQUEST_URI} !^/backend/ + RewriteRule ^(.*)$ /frontend/index.html [L] + + +# Security headers + + Header always set X-Content-Type-Options nosniff + Header always set X-Frame-Options SAMEORIGIN + Header always set X-XSS-Protection "1; mode=block" + + +# Cache static assets + + ExpiresActive on + ExpiresByType text/css "access plus 1 year" + ExpiresByType application/javascript "access plus 1 year" + ExpiresByType image/png "access plus 1 year" + ExpiresByType image/jpg "access plus 1 year" + ExpiresByType image/jpeg "access plus 1 year" + ExpiresByType image/gif "access plus 1 year" + ExpiresByType image/webp "access plus 1 year" + ExpiresByType video/mp4 "access plus 1 month" + +EOF + +# Create combined deployment instructions +cat > development/README.md << 'EOF' +# That's Me - Development Deployment + +## Structure +``` +development/ +β”œβ”€β”€ frontend/ # Quasar SPA build +β”‚ β”œβ”€β”€ index.html +β”‚ β”œβ”€β”€ js/ +β”‚ β”œβ”€β”€ css/ +β”‚ β”œβ”€β”€ images/ +β”‚ β”œβ”€β”€ videos/ +β”‚ └── .htaccess +β”œβ”€β”€ backend/ # Laravel API +β”‚ β”œβ”€β”€ app/ +β”‚ β”œβ”€β”€ public/ +β”‚ β”‚ └── index.php +β”‚ β”œβ”€β”€ routes/ +β”‚ β”œβ”€β”€ .env.production +β”‚ └── ... +β”œβ”€β”€ .htaccess # Root routing +└── README.md +``` + +## Deployment Instructions + +### Option 1: Combined Deployment (Single Domain) +1. Upload entire `development/` folder contents to web root +2. Configure backend: + - Rename `backend/.env.production` to `backend/.env` + - Generate APP_KEY (see below) + - Set permissions: 755 for `backend/storage/` and `backend/bootstrap/cache/` + +### Option 2: Separate Subdomains +- Frontend: Upload `frontend/` contents to frontend subdomain +- Backend: Upload `backend/` contents to backend subdomain + +## Generate Laravel APP_KEY +Create temporary file in web root: +```php + +``` + +## URL Structure (Combined) +- **Frontend**: `yourdomain.com/` (Quasar LifeWave SPA) +- **API**: `yourdomain.com/api/health`, `/api/life-events`, `/api/entries/{id}` +- **Backend Admin**: `yourdomain.com/admin/` (if Livewire/Volt components added) + +## Features +- βœ… LifeWave visualization with anime.js +- βœ… Mock life events data for development +- βœ… Database-free operation +- βœ… CORS configured for cross-origin requests +- βœ… File-based sessions and cache +- βœ… SPA routing for Vue Router + +## Testing +- Health check: `/api/health` +- Life events: `/api/life-events` (returns events with animation config) +- Entry detail: `/api/entries/1` + +Perfect for development and demo environments! +EOF + +# Create individual deployment instructions +cat > development/frontend/DEPLOYMENT_INSTRUCTIONS.md << 'EOF' +# Frontend Deployment + +## Standalone Frontend Deployment +Upload contents of this folder to web root for frontend-only deployment. + +## What's Included +- Complete Quasar SPA build with LifeWave visualization +- Images, videos, and audio assets +- SPA routing via .htaccess +- Development configuration + +## Dependencies +- Backend API for data (configure API_BASE_URL in config.js) +- anime.js for wave animations (included in build) +EOF + +cat > development/backend/DEPLOYMENT_INSTRUCTIONS.md << 'EOF' +# Backend Deployment + +## Laravel API Deployment +Upload contents of this folder to web root for backend-only deployment. + +## Setup Steps +1. Rename `.env.production` to `.env` +2. Generate APP_KEY using provided instructions +3. Set file permissions: 755 for storage/ and bootstrap/cache/ +4. Test API endpoints + +## API Endpoints +- Health: `/api/health` +- Life Events: `/api/life-events` (LifeWave data with animation config) +- Entry Details: `/api/entries/{id}` + +## Features +- Database-free operation with mock data +- CORS configured for frontend integration +- Optimized for anime.js LifeWave visualizations +EOF + +echo "βœ… Development deployment structure created successfully!" +echo "" +echo "πŸ“ Created development structure:" +echo " - development/frontend/ (Quasar SPA)" +echo " - development/backend/ (Laravel API)" +echo " - development/.htaccess (Combined routing)" +echo "" +echo "🎯 Deployment Options:" +echo " 1. Combined: Upload entire development/ folder" +echo " 2. Separate: Upload frontend/ and backend/ to different domains" +echo "" +echo "🌊 Features:" +echo " - LifeWave visualization ready" +echo " - Mock data with animation config" +echo " - Database-free operation" +echo " - anime.js integration support" +echo "" +echo "πŸ“‹ Next: Follow README.md in development/ folder" \ No newline at end of file