# Deployment Guide — boha-app-ts (Ubuntu Server) Migration from PHP boha-app to TypeScript boha-app-ts on the same Ubuntu server. Both apps share the same MySQL database. The PHP app stays running during migration. --- ## Prerequisites - Ubuntu server with the PHP boha-app already running - nginx with SSL (Let's Encrypt) already configured - MySQL database already running with production data - NAS storage mounted (e.g., `/mnt/nas/02_PROJEKTY`) - SSH access to the server --- ## Phase 1: Prepare on Dev Machine (Windows) ### 1.1 Create Prisma migration baseline ```bash cd D:\cortex\boha-app-ts mkdir -p prisma/migrations/0_init npx prisma migrate diff --from-empty --to-schema-datamodel prisma/schema.prisma --script > prisma/migrations/0_init/migration.sql npx prisma migrate resolve --applied 0_init git add prisma/migrations/ git commit -m "chore: create Prisma migration baseline" ``` ### 1.2 Build the application ```bash npm run build ``` This creates: - `dist/` — compiled server (Node.js) - `dist-client/` — compiled frontend (static files) ### 1.3 Generate new production secrets ```bash openssl rand -hex 32 # Save this as JWT_SECRET openssl rand -hex 32 # Save this as TOTP_ENCRYPTION_KEY (only if you want a new key) ``` ### 1.4 Test the production build locally (optional) ```bash APP_ENV=production JWT_SECRET= TOTP_ENCRYPTION_KEY= DATABASE_URL= node dist/server.js ``` Verify it starts and responds at `http://localhost:3001/api/health`. --- ## Phase 2: Prepare Ubuntu Server ### 2.1 Install Node.js 22 ```bash curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash - sudo apt-get install -y nodejs node -v npm -v ``` ### 2.2 Install PM2 ```bash sudo npm install -g pm2 ``` ### 2.3 Create application directory ```bash sudo mkdir -p /var/www/boha-app-ts sudo chown $USER:$USER /var/www/boha-app-ts ``` --- ## Phase 3: Transfer Files to Server ### 3.1 Copy built files From your Windows machine (Git Bash or PowerShell with SCP): ```bash scp -r dist/ dist-client/ package.json package-lock.json prisma/ scripts/ .env.example user@server:/var/www/boha-app-ts/ ``` Or use rsync if available: ```bash rsync -avz --exclude node_modules --exclude .env dist/ dist-client/ package.json package-lock.json prisma/ scripts/ .env.example user@server:/var/www/boha-app-ts/ ``` ### 3.2 Install production dependencies on server ```bash ssh user@server cd /var/www/boha-app-ts npm install --production npx prisma generate ``` --- ## Phase 4: Configure Environment ### 4.1 Create production .env ```bash cd /var/www/boha-app-ts cp .env.example .env nano .env ``` Fill in: ```env # Database — same as the PHP app DATABASE_URL=mysql://user:password@localhost:3306/your_db_name # Server PORT=3001 HOST=127.0.0.1 APP_ENV=production # Auth — use the NEW secrets generated in step 1.3 JWT_SECRET= ACCESS_TOKEN_EXPIRY=900 REFRESH_TOKEN_SESSION_EXPIRY=3600 REFRESH_TOKEN_REMEMBER_EXPIRY=2592000 # TOTP — use SAME key as PHP app (unless you want to re-encrypt) TOTP_ENCRYPTION_KEY= # NAS — Linux mount point NAS_PATH=/mnt/nas/02_PROJEKTY MAX_UPLOAD_SIZE=52428800 # Email CONTACT_EMAIL_TO=manager@boha-automation.cz CONTACT_EMAIL_FROM=web@boha-automation.cz SMTP_FROM=noreply@boha-automation.cz # CORS — your production domain(s) CORS_ORIGINS=https://app.boha-automation.cz,https://www.boha-automation.cz ``` **Important decisions:** | Setting | Recommendation | |---------|---------------| | `JWT_SECRET` | **New key.** All PHP sessions will be invalid — users re-login. This is expected. | | `TOTP_ENCRYPTION_KEY` | **Same key as PHP app.** Avoids re-encrypting all TOTP secrets. | | `DATABASE_URL` | **Same database as PHP app.** Both apps share it. | | `NAS_PATH` | **Linux mount point** instead of Windows drive letter. | --- ## Phase 5: Database Setup ### 5.1 Mark Prisma baseline as applied ```bash cd /var/www/boha-app-ts npx prisma migrate resolve --applied 0_init ``` This tells Prisma the database already has all tables. No SQL is executed. ### 5.2 Verify database connection ```bash npx prisma db pull --print | head -20 ``` Should show your existing tables. --- ## Phase 6: TOTP Key Rotation (only if using new encryption key) **Skip this section if you're using the same `TOTP_ENCRYPTION_KEY` as the PHP app.** If you generated a new encryption key: ```bash cd /var/www/boha-app-ts # Dry run — verify all secrets can be decrypted and re-encrypted npx tsx scripts/rotate-totp-key.ts --dry-run # If all [OK], run for real npx tsx scripts/rotate-totp-key.ts ``` After this, the PHP app's TOTP verification will break (secrets are now encrypted with the new key). Only do this when you're ready to cut over. --- ## Phase 7: Start Application with PM2 ### 7.1 Create PM2 config ```bash cd /var/www/boha-app-ts cat > ecosystem.config.js << 'EOF' module.exports = { apps: [{ name: 'boha-app-ts', script: 'dist/server.js', cwd: '/var/www/boha-app-ts', instances: 1, env: { NODE_ENV: 'production', }, }] }; EOF ``` ### 7.2 Start the app ```bash pm2 start ecosystem.config.js pm2 save pm2 startup # Follow the printed command to enable auto-start on boot ``` ### 7.3 Verify ```bash pm2 status pm2 logs boha-app-ts --lines 20 curl http://localhost:3001/api/health ``` Expected: `{"status":"ok","timestamp":"..."}` --- ## Phase 8: Nginx Configuration ### 8.1 Create nginx config ```bash sudo nano /etc/nginx/sites-available/boha-app-ts ``` Paste: ```nginx server { listen 443 ssl http2; server_name app.boha-automation.cz; ssl_certificate /etc/letsencrypt/live/app.boha-automation.cz/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/app.boha-automation.cz/privkey.pem; client_max_body_size 55M; location / { proxy_pass http://127.0.0.1:3001; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection 'upgrade'; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_cache_bypass $http_upgrade; } } server { listen 80; server_name app.boha-automation.cz; return 301 https://$host$request_uri; } ``` Adjust `server_name` and SSL paths to match your setup. ### 8.2 Enable and reload ```bash sudo ln -s /etc/nginx/sites-available/boha-app-ts /etc/nginx/sites-enabled/ sudo nginx -t sudo systemctl reload nginx ``` --- ## Phase 9: Testing ### 9.1 Verify in browser Open `https://app.boha-automation.cz` and test: - [ ] Login page loads - [ ] Login works (users will need to re-login due to new JWT_SECRET) - [ ] TOTP verification works (if using same encryption key) - [ ] Dashboard loads with data - [ ] Offers — list, create, edit, PDF export - [ ] Orders — list, create from offer, status transitions - [ ] Invoices — list, create, PDF with QR code - [ ] Projects — list, create, file manager (upload/download) - [ ] Attendance — clock in/out, admin view, print - [ ] Trips — list, history - [ ] Settings — company settings, users, roles ### 9.2 Check logs for errors ```bash pm2 logs boha-app-ts --lines 50 ``` --- ## Phase 10: Cutover Strategy Both apps run simultaneously on the same database. Recommended approach: 1. **Week 1:** Run both apps. Use the TS app for daily work. Fall back to PHP if issues arise. 2. **Week 2:** If stable, redirect the main domain to the TS app. 3. **Week 3:** Stop the PHP app. To redirect the PHP domain to the TS app, update the nginx config for the PHP domain to proxy to port 3001 instead. --- ## Future Updates When you push code changes: ```bash # On dev machine npm run build git push # On server cd /var/www/boha-app-ts git pull npm install --production npx prisma generate npx prisma migrate deploy # runs any new migrations pm2 restart boha-app-ts ``` --- ## Troubleshooting | Problem | Solution | |---------|----------| | `EADDRINUSE: port 3001` | `pm2 stop boha-app-ts` then `pm2 start` | | Prisma connection error | Check `DATABASE_URL` in `.env` | | TOTP verification fails | Verify `TOTP_ENCRYPTION_KEY` matches the key used to encrypt secrets | | NAS files not accessible | Check mount: `ls /mnt/nas/02_PROJEKTY`, verify permissions | | 502 Bad Gateway | App not running: `pm2 status`, check logs: `pm2 logs` | | CSS/JS not loading | Verify `dist-client/` was copied, check `APP_ENV=production` | | CORS errors | Check `CORS_ORIGINS` in `.env` matches your domain exactly | --- ## Quick Reference | Command | Purpose | |---------|---------| | `pm2 start ecosystem.config.js` | Start the app | | `pm2 restart boha-app-ts` | Restart after update | | `pm2 stop boha-app-ts` | Stop the app | | `pm2 logs boha-app-ts` | View logs | | `pm2 monit` | Live monitoring | | `npx prisma migrate deploy` | Apply database migrations | | `npx prisma studio` | Database GUI (dev only) |