Initial commit

This commit is contained in:
s4luorth
2026-02-07 13:04:04 +01:00
commit 5e0fceab15
82 changed files with 30348 additions and 0 deletions

View File

@@ -0,0 +1,406 @@
const fs = require('fs').promises;
const fsSync = require('fs');
const path = require('path');
const SOURCE_DIR = __dirname;
const DEPLOY_DIR = path.join(__dirname, '..', 'DEPLOYMENT_READY');
// Dateien und Ordner die KOPIERT werden sollen
const INCLUDE_FILES = [
// Docker
'Dockerfile',
'docker-compose.yml',
'.dockerignore',
// Package
'package.json',
'package-lock.json',
// Source Code
'src/**/*',
// Fonts
'fonts/**/*.svg',
// Config Example
'.env.example'
];
// Dateien die NICHT kopiert werden sollen
const EXCLUDE_PATTERNS = [
'node_modules',
'output',
'cache',
'.git',
'bruno-tests',
'*.md',
'test-*.js',
'test-*.json',
'test-*.sh',
'generate-*.js',
'server.log',
'.env',
'deploy.sh',
'prepare-deployment.js',
'DEPLOYMENT_READY'
];
function shouldExclude(filePath) {
const relativePath = path.relative(SOURCE_DIR, filePath);
return EXCLUDE_PATTERNS.some(pattern => {
if (pattern.includes('*')) {
const regex = new RegExp('^' + pattern.replace(/\*/g, '.*') + '$');
return regex.test(path.basename(filePath)) || regex.test(relativePath);
}
return relativePath.startsWith(pattern) || path.basename(filePath) === pattern;
});
}
async function ensureDir(dir) {
try {
await fs.mkdir(dir, { recursive: true });
} catch (err) {
if (err.code !== 'EEXIST') throw err;
}
}
async function copyFile(src, dest) {
await ensureDir(path.dirname(dest));
await fs.copyFile(src, dest);
}
async function removeDir(dir) {
try {
const entries = await fs.readdir(dir, { withFileTypes: true });
for (const entry of entries) {
const fullPath = path.join(dir, entry.name);
if (entry.isDirectory()) {
await removeDir(fullPath);
} else {
await fs.unlink(fullPath);
}
}
await fs.rmdir(dir);
} catch (err) {
if (err.code !== 'ENOENT') throw err;
}
}
async function pathExists(p) {
try {
await fs.access(p);
return true;
} catch {
return false;
}
}
async function copyDirectory(src, dest) {
const entries = await fs.readdir(src, { withFileTypes: true });
await ensureDir(dest);
for (const entry of entries) {
const srcPath = path.join(src, entry.name);
const destPath = path.join(dest, entry.name);
if (shouldExclude(srcPath)) {
console.log(`⏭️ Skipping: ${path.relative(SOURCE_DIR, srcPath)}`);
continue;
}
if (entry.isDirectory()) {
await copyDirectory(srcPath, destPath);
} else {
await copyFile(srcPath, destPath);
console.log(`✅ Copied: ${path.relative(SOURCE_DIR, srcPath)}`);
}
}
}
async function main() {
console.log('🚀 Preparing Deployment Package...\n');
// Deployment-Verzeichnis erstellen/leeren
if (await pathExists(DEPLOY_DIR)) {
console.log('🗑️ Cleaning existing deployment directory...');
await removeDir(DEPLOY_DIR);
}
await ensureDir(DEPLOY_DIR);
console.log(`📁 Created: ${DEPLOY_DIR}\n`);
// Dateien kopieren
console.log('📋 Copying production files...\n');
await copyDirectory(SOURCE_DIR, DEPLOY_DIR);
// Produktions-.env.example erstellen
const envExample = `# Skrift Backend - Production Environment Variables
# Scriptalizer API Configuration
SCRIPTALIZER_LICENSE_KEY=f9918b40-d11c-11f0-b558-0800200c9a66
SCRIPTALIZER_ERR_FREQUENCY=0
# Preview Settings
BATCH_SIZE=30
CACHE_LIFETIME_HOURS=2
RATE_LIMIT_PER_MINUTE=2
# Environment
NODE_ENV=production
PORT=4000
`;
await fs.writeFile(path.join(DEPLOY_DIR, '.env.example'), envExample);
console.log('✅ Created: .env.example\n');
// README für Deployment erstellen
const deployReadme = `# Skrift Backend - Deployment Package
Dieses Verzeichnis enthält alle notwendigen Dateien für das Deployment auf den Server.
## Schnellstart
### 1. Zum Server kopieren
\`\`\`bash
# Mit SCP
scp -r * root@DEIN-SERVER:/opt/skrift-backend/
# Oder mit rsync (falls verfügbar)
rsync -avz ./ root@DEIN-SERVER:/opt/skrift-backend/
\`\`\`
### 2. Auf dem Server einrichten
\`\`\`bash
ssh root@DEIN-SERVER
cd /opt/skrift-backend
# .env erstellen (aus .env.example)
cp .env.example .env
nano .env # Prüfen und anpassen falls nötig
# Output-Verzeichnis erstellen
mkdir -p /var/skrift-output
chmod 755 /var/skrift-output
# Container starten
docker-compose up -d --build
# Logs prüfen
docker-compose logs -f
\`\`\`
### 3. Testen
\`\`\`bash
curl http://localhost:4000/health
\`\`\`
## Enthaltene Dateien
- \`src/\` - Backend Source Code
- \`fonts/\` - SVG Fonts (Tilda, Alva, Ellie)
- \`Dockerfile\` - Docker Image Konfiguration
- \`docker-compose.yml\` - Docker Compose Konfiguration
- \`package.json\` - Node.js Dependencies
- \`.env.example\` - Environment Variables Template
## Wichtig
⚠️ **SCRIPTALIZER_ERR_FREQUENCY=0** ist bereits gesetzt - keine durchgestrichenen Wörter!
## Nginx Proxy Manager
Nach dem Start in Nginx Proxy Manager konfigurieren:
- Domain: backend.deine-domain.de
- Forward to: skrift-backend:4000
- SSL: Let's Encrypt aktivieren
## Support
Bei Problemen: \`docker-compose logs -f\`
`;
await fs.writeFile(path.join(DEPLOY_DIR, 'README.txt'), deployReadme);
console.log('✅ Created: README.txt\n');
// Upload-Script erstellen
const uploadScript = `#!/bin/bash
# Skrift Backend - Upload Script
# Dieses Script lädt das Backend auf den Server hoch
# KONFIGURATION - BITTE ANPASSEN!
SERVER_USER="root"
SERVER_HOST="" # z.B. "123.456.789.0" oder "dein-server.de"
SERVER_PATH="/opt/skrift-backend"
# Farben für Output
RED='\\033[0;31m'
GREEN='\\033[0;32m'
YELLOW='\\033[1;33m'
NC='\\033[0m' # No Color
# Funktion: Fehler anzeigen und beenden
error_exit() {
echo -e "\${RED}❌ ERROR: \$1\${NC}" >&2
exit 1
}
# Prüfen ob Server konfiguriert ist
if [ -z "$SERVER_HOST" ]; then
error_exit "SERVER_HOST ist nicht gesetzt! Bitte in upload.sh die Variable SERVER_HOST setzen."
fi
echo -e "\${GREEN}🚀 Skrift Backend Upload\${NC}"
echo "======================================"
echo "Server: \$SERVER_USER@\$SERVER_HOST"
echo "Path: \$SERVER_PATH"
echo ""
# Prüfen ob SSH-Verbindung funktioniert
echo -e "\${YELLOW}🔍 Testing SSH connection...\${NC}"
ssh -o ConnectTimeout=5 -o BatchMode=yes \$SERVER_USER@\$SERVER_HOST "echo '✅ SSH connection successful'" || error_exit "SSH connection failed"
echo ""
# Verzeichnis auf Server erstellen
echo -e "\${YELLOW}📁 Creating directory on server...\${NC}"
ssh \$SERVER_USER@\$SERVER_HOST "mkdir -p \$SERVER_PATH" || error_exit "Failed to create directory"
echo ""
# Dateien hochladen
echo -e "\${YELLOW}📤 Uploading files...\${NC}"
scp -r * \$SERVER_USER@\$SERVER_HOST:\$SERVER_PATH/ || error_exit "Upload failed"
echo ""
echo -e "\${GREEN}✅ Upload successful!\${NC}"
echo ""
echo "Next steps:"
echo "1. SSH to server: ssh \$SERVER_USER@\$SERVER_HOST"
echo "2. Go to directory: cd \$SERVER_PATH"
echo "3. Create .env: cp .env.example .env"
echo "4. Create output dir: mkdir -p /var/skrift-output"
echo "5. Start container: docker-compose up -d --build"
echo "6. Check logs: docker-compose logs -f"
`;
await fs.writeFile(path.join(DEPLOY_DIR, 'upload.sh'), uploadScript);
await fs.chmod(path.join(DEPLOY_DIR, 'upload.sh'), 0o755);
console.log('✅ Created: upload.sh\n');
// Windows Batch Upload-Script
const uploadBat = `@echo off
REM Skrift Backend - Windows Upload Script
REM KONFIGURATION - BITTE ANPASSEN!
set SERVER_USER=root
set SERVER_HOST=
set SERVER_PATH=/opt/skrift-backend
if "%SERVER_HOST%"=="" (
echo ERROR: SERVER_HOST ist nicht gesetzt!
echo Bitte in upload.bat die Variable SERVER_HOST setzen.
pause
exit /b 1
)
echo ========================================
echo Skrift Backend Upload
echo ========================================
echo Server: %SERVER_USER%@%SERVER_HOST%
echo Path: %SERVER_PATH%
echo.
echo Uploading files...
echo.
scp -r * %SERVER_USER%@%SERVER_HOST%:%SERVER_PATH%/
if %ERRORLEVEL% NEQ 0 (
echo.
echo ERROR: Upload fehlgeschlagen!
pause
exit /b 1
)
echo.
echo ========================================
echo Upload erfolgreich!
echo ========================================
echo.
echo Naechste Schritte:
echo 1. SSH to server: ssh %SERVER_USER%@%SERVER_HOST%
echo 2. Go to directory: cd %SERVER_PATH%
echo 3. Create .env: cp .env.example .env
echo 4. Create output dir: mkdir -p /var/skrift-output
echo 5. Start container: docker-compose up -d --build
echo 6. Check logs: docker-compose logs -f
echo.
pause
`;
await fs.writeFile(path.join(DEPLOY_DIR, 'upload.bat'), uploadBat);
console.log('✅ Created: upload.bat\n');
// Statistik
const stats = await getDirectoryStats(DEPLOY_DIR);
console.log('');
console.log('📊 Deployment Package Stats:');
console.log('=====================================');
console.log(`📁 Total Files: ${stats.files}`);
console.log(`📂 Total Directories: ${stats.dirs}`);
console.log(`💾 Total Size: ${formatBytes(stats.size)}`);
console.log('');
console.log('✅ Deployment Package Ready!');
console.log('');
console.log(`📦 Location: ${DEPLOY_DIR}`);
console.log('');
console.log('Next steps:');
console.log('1. Gehe ins Verzeichnis: cd DEPLOYMENT_READY');
console.log('2. Passe upload.sh oder upload.bat an (SERVER_HOST setzen)');
console.log('3. Führe aus: ./upload.sh (Linux/Mac) oder upload.bat (Windows)');
}
async function getDirectoryStats(dir) {
let files = 0;
let dirs = 0;
let size = 0;
const entries = await fs.readdir(dir, { withFileTypes: true });
for (const entry of entries) {
const fullPath = path.join(dir, entry.name);
if (entry.isDirectory()) {
dirs++;
const subStats = await getDirectoryStats(fullPath);
files += subStats.files;
dirs += subStats.dirs;
size += subStats.size;
} else {
files++;
const stat = await fs.stat(fullPath);
size += stat.size;
}
}
return { files, dirs, size };
}
function formatBytes(bytes) {
if (bytes === 0) return '0 Bytes';
const k = 1024;
const sizes = ['Bytes', 'KB', 'MB', 'GB'];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return Math.round(bytes / Math.pow(k, i) * 100) / 100 + ' ' + sizes[i];
}
main().catch(err => {
console.error('❌ Error:', err.message);
process.exit(1);
});