Import aus Monorepo (frischer Start)
All checks were successful
Build & Deploy / deploy (push) Successful in 10s

This commit is contained in:
Lucas Orth
2026-08-24 12:13:50 +02:00
commit 0ddaab27d0
34 changed files with 12768 additions and 0 deletions

93
src/server.js Normal file
View File

@@ -0,0 +1,93 @@
const express = require('express');
const cors = require('cors');
const config = require('./config');
const previewRoutes = require('./api/routes/preview-routes');
const orderRoutes = require('./api/routes/order-routes');
const chargeRoutes = require('./api/routes/charge-routes');
const healthRoutes = require('./api/routes/health-routes');
const errorHandler = require('./api/middleware/error-handler');
const requestLogger = require('./api/middleware/request-logger');
const { applyRenderFormats, setFormatMissHandler } = require('./lib/page-layout');
const { fetchRenderFormats } = require('./services/directus-service');
// Zentrale Format-Definitionen aus Directus in den Cache holen. Läuft beim Start
// und stündlich; Fehler sind unkritisch (die Defaults im page-layout greifen).
let lastFormatRefresh = 0;
async function refreshRenderFormats() {
lastFormatRefresh = Date.now();
try {
const rows = await fetchRenderFormats();
applyRenderFormats(rows);
console.log(`[Formate] ${Array.isArray(rows) ? rows.length : 0} Format(e) aus Directus geladen.`);
} catch (e) {
console.warn(`[Formate] Konnte Directus-Formate nicht laden (nutze Defaults): ${e.message}`);
}
}
// Unbekanntes Format angefragt → sofort nachladen (max. alle 30 s, damit ein
// dauerhaft unbekanntes Format kein Dauerfeuer auslöst).
setFormatMissHandler((key) => {
if (Date.now() - lastFormatRefresh < 30 * 1000) return;
console.log(`[Formate] Unbekanntes Format "${key}" angefragt – lade Formate nach.`);
refreshRenderFormats();
});
const app = express();
// Middleware
app.use(cors(config.cors));
app.use(express.json({ limit: '10mb' }));
app.use(express.urlencoded({ extended: true, limit: '10mb' }));
app.use(requestLogger);
// Routes
app.use('/health', healthRoutes);
app.use('/api/preview', previewRoutes);
app.use('/api/order', orderRoutes);
app.use('/api/charge', chargeRoutes);
// Format-Cache manuell auffrischen (Token-geschützt) – für „sofort übernehmen".
app.post('/api/formats/refresh', async (req, res) => {
const token = config.auth && config.auth.apiToken;
if (token && req.headers['x-api-token'] !== token) {
return res.status(401).json({ error: 'API token required' });
}
await refreshRenderFormats();
res.json({ ok: true });
});
// Error handling
app.use(errorHandler);
// Start server
app.listen(config.port, () => {
console.log('╔════════════════════════════════════════════════════════════╗');
console.log('║ Skrift Backend Server ║');
console.log('╚════════════════════════════════════════════════════════════╝');
console.log(`Environment: ${config.env}`);
console.log(`Port: ${config.port}`);
console.log(`Batch Size: Unlimited (auto-split to ${config.preview.scriptalizerBatchSize} for API)`);
console.log(`Cache: Disabled`);
console.log(`Rate Limit: Disabled`);
console.log(`Scriptalizer: ${config.scriptalizer.licenseKey ? 'Configured ✓' : 'Missing ✗'}`);
console.log('════════════════════════════════════════════════════════════');
console.log(`Server running at http://localhost:${config.port}`);
console.log('════════════════════════════════════════════════════════════\n');
// Formate initial laden und stündlich auffrischen (zentral aus Directus).
refreshRenderFormats();
setInterval(refreshRenderFormats, 60 * 60 * 1000);
});
// Graceful shutdown
process.on('SIGTERM', () => {
console.log('SIGTERM received, shutting down gracefully...');
process.exit(0);
});
process.on('SIGINT', () => {
console.log('\nSIGINT received, shutting down gracefully...');
process.exit(0);
});