#!/bin/bash # filepath: /Users/tbehrend/Repositories/thatsme/deploy.sh echo "πŸš€ Creating deployment packages for 'That's Me' deployment structure..." # Clean up previous deployment rm -rf deployment mkdir -p deployment/{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/* deployment/frontend/ cp -r frontend/public/images deployment/frontend/ cp -r frontend/public/videos deployment/frontend/ if [ -d "frontend/public/audio" ]; then cp -r frontend/public/audio deployment/frontend/ fi # Create frontend config for deployment cat > deployment/frontend/config.js << 'EOF' // Frontend configuration for deployment window.APP_CONFIG = { API_BASE_URL: '/api', APP_URL: window.location.origin, environment: 'production', database: false }; EOF # Update frontend index.html to include config sed -i.bak 's|| \n |' deployment/frontend/index.html # Create frontend .htaccess for SPA routing cat > deployment/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 deployment/backend/{app,bootstrap,config,database,resources,routes,storage,vendor,public} # Copy Laravel core files cp -r backend/app deployment/backend/ cp -r backend/bootstrap deployment/backend/ cp -r backend/config deployment/backend/ cp -r backend/database deployment/backend/ cp -r backend/resources deployment/backend/ cp -r backend/routes deployment/backend/ cp -r backend/storage deployment/backend/ cp -r backend/vendor deployment/backend/ # Copy backend root files cp backend/artisan deployment/backend/ cp backend/composer.json deployment/backend/ cp backend/composer.lock deployment/backend/ if [ -f "backend/vite.config.js" ]; then cp backend/vite.config.js deployment/backend/ fi # Copy built assets to public if [ -d "backend/public/build" ]; then cp -r backend/public/build deployment/backend/public/ fi # Copy other public assets if [ -d "backend/public" ]; then rsync -av --exclude='build' backend/public/ deployment/backend/public/ fi # Create backend index.php for deployment structure cat > deployment/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 > deployment/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 deployment 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 > deployment/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' => 'deployment-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 (Deployment)', 'frontend_path' => '../frontend/', 'api_endpoints' => [ 'health' => '/api/health', 'life_events' => '/api/life-events', 'entry_detail' => '/api/entries/{id}' ], 'note' => 'Database-free deployment mode with mock LifeWave data' ]); }); EOF # Create backend environment file for deployment cat > deployment/backend/.env.production << 'EOF' APP_NAME="That's Me Backend (Deployment)" 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 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 > deployment/.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 > deployment/README.md << 'EOF' # That's Me - Production Deployment ## Structure ``` deployment/ β”œβ”€β”€ 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 `deployment/` 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 deployment - βœ… 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 production and demo environments! EOF # Create individual deployment instructions cat > deployment/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 - Production configuration ## Dependencies - Backend API for data (configure API_BASE_URL in config.js) - anime.js for wave animations (included in build) EOF cat > deployment/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 "βœ… Deployment structure created successfully!" echo "" echo "πŸ“ Created deployment structure:" echo " - deployment/frontend/ (Quasar SPA)" echo " - deployment/backend/ (Laravel API)" echo " - deployment/.htaccess (Combined routing)" echo "" echo "🎯 Deployment Options:" echo " 1. Combined: Upload entire deployment/ 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 deployment/ folder"