Files
skrift-backend/src/server.js
s4luorth a6eb41f996
All checks were successful
Build & Deploy / deploy (push) Successful in 16s
Batch: FTP-Cron standardmaessig aus (Standardweg = Uebernahme in Produktion)
Der taegliche 03:00-FTP-Buendel-Lauf laeuft nur noch, wenn
SKRIFT_BATCH_FTP_CRON=true gesetzt ist. Ohne Flag kein automatischer
FTP-Upload; Uebermittlungen laufen ueber die Uebernahme ins Board.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-28 10:15:01 +02:00

114 lines
5.1 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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 batchRoutes = require('./api/routes/batch-routes');
const healthRoutes = require('./api/routes/health-routes');
const { runScheduledBatch, berlinParts } = require('./api/controllers/batch-controller');
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 5 s, damit ein
// dauerhaft unbekanntes Format kein Dauerfeuer auslöst). Neu in Directus angelegte
// Formate sind damit ohne Backend-Neustart binnen weniger Sekunden aktiv.
setFormatMissHandler((key) => {
if (Date.now() - lastFormatRefresh < 5 * 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);
app.use('/api/batch', batchRoutes);
// 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);
// Batch-FTP-Bündelung nur, wenn ausdrücklich aktiviert (Standardweg ist die
// Übernahme in die Produktion, nicht FTP). SKRIFT_BATCH_FTP_CRON=true schaltet
// den täglichen 03:00-Lauf (Europe/Berlin) wieder ein; Sa+So am Montag.
if (String(process.env.SKRIFT_BATCH_FTP_CRON || '').toLowerCase() === 'true') {
let letzterBatchTag = null;
setInterval(() => {
try {
const { date, hour } = berlinParts();
if (hour !== 3 || letzterBatchTag === date) return;
letzterBatchTag = date;
runScheduledBatch().catch((e) => console.error('[batch-cron] Fehler:', e.message));
} catch (e) { console.error('[batch-cron] Tick-Fehler:', e.message); }
}, 60 * 1000);
console.log('Batch-FTP-Cron: aktiv (03:00 Europe/Berlin)');
}
});
// 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);
});