Files
Projektarbeit-MYP/backend/static/sw.js
Till Tomczak b1ae9523a9 🔧 Update: Workflow Documentation and Job Deletion Enhancements
**Änderungen:**
-  Aktualisierte Schulungsdokumentation für den Gastzugang, um den Workflow klarer darzustellen.
-  Verbesserte Visualisierung im Workflow-Diagramm, um den Prozess für Gäste zu verdeutlichen.
-  Optimierte Logik in der Job-Löschfunktion, um abhängige Datensätze vor der Löschung zu bereinigen.

**Ergebnis:**
- Klarere Anleitungen für Benutzer zur Nutzung des Gastzugangs.
- Verbesserte Nachvollziehbarkeit des Workflows durch aktualisierte Diagramme.
- Erhöhte Datenintegrität durch Bereinigung abhängiger Datensätze vor der Job-Löschung.

🤖 Generated with [Claude Code](https://claude.ai/code)
2025-06-16 01:18:31 +02:00

393 lines
13 KiB
JavaScript

/**
* MYP Service Worker
* =================
*
* Service Worker für das Mercedes-Benz 3D-Druck-Management-System
* Bietet Offline-Funktionalität und Caching für bessere Performance
*/
const CACHE_NAME = 'myp-v1.0.0';
const STATIC_CACHE_NAME = 'myp-static-v1.0.0';
const DYNAMIC_CACHE_NAME = 'myp-dynamic-v1.0.0';
// Statische Ressourcen, die immer gecacht werden sollen
const STATIC_ASSETS = [
'/',
'/static/css/tailwind.min.css',
'/static/css/dark-light-unified.css',
'/static/fontawesome/css/all.min.css',
'/static/js/jobs-safety-fix.js',
'/static/manifest.json',
'/static/favicon.svg',
'/static/icons/icon-192.png',
'/static/icons/icon-512.png'
];
// API-Endpunkte, die gecacht werden können
const CACHEABLE_APIS = [
'/api/printers',
'/api/jobs',
'/api/stats'
];
// Installation des Service Workers
self.addEventListener('install', event => {
console.log('🔧 MYP Service Worker wird installiert...');
event.waitUntil(
caches.open(STATIC_CACHE_NAME)
.then(cache => {
console.log('📦 Statische Assets werden gecacht...');
return cache.addAll(STATIC_ASSETS);
})
.then(() => {
console.log('✅ MYP Service Worker erfolgreich installiert');
return self.skipWaiting();
})
.catch(error => {
console.error('❌ Fehler bei Service Worker Installation:', error);
})
);
});
// Aktivierung des Service Workers
self.addEventListener('activate', event => {
console.log('🚀 MYP Service Worker wird aktiviert...');
event.waitUntil(
caches.keys()
.then(cacheNames => {
return Promise.all(
cacheNames.map(cacheName => {
// Alte Caches löschen
if (cacheName !== STATIC_CACHE_NAME &&
cacheName !== DYNAMIC_CACHE_NAME &&
cacheName !== CACHE_NAME) {
console.log('🗑️ Lösche alten Cache:', cacheName);
return caches.delete(cacheName);
}
})
);
})
.then(() => {
console.log('✅ MYP Service Worker aktiviert');
return self.clients.claim();
})
);
});
// Fetch-Event Handler für Caching-Strategien
self.addEventListener('fetch', event => {
try {
const request = event.request;
// Basis-Validierung der Anfrage
if (!request || !request.url) {
console.warn('🚫 Ungültige Anfrage erhalten:', request);
return;
}
const url = new URL(request.url);
// Nur GET-Requests cachen
if (request.method !== 'GET') {
return;
}
// Bestimmte Dateitypen überspringen
if (url.pathname.includes('.woff') ||
url.pathname.includes('.ttf') ||
url.pathname.includes('.eot') ||
url.pathname.endsWith('.map')) {
return;
}
} catch (error) {
console.error('❌ Fehler bei fetch event verarbeitung:', error);
return;
}
// Statische Assets: Cache First
if (STATIC_ASSETS.some(asset => url.pathname.endsWith(asset) || url.pathname === asset)) {
event.respondWith(cacheFirst(request));
return;
}
// API-Endpunkte: Network First mit Cache Fallback
if (CACHEABLE_APIS.some(api => url.pathname.startsWith(api))) {
event.respondWith(networkFirst(request));
return;
}
// Statische Dateien (CSS, JS, Bilder): Cache First
if (url.pathname.startsWith('/static/')) {
event.respondWith(cacheFirst(request));
return;
}
// HTML-Seiten: Network First
if (request.headers.get('accept') && request.headers.get('accept').includes('text/html')) {
event.respondWith(networkFirst(request));
return;
}
// Alle anderen Requests: Network Only mit besserer Error-Behandlung
event.respondWith(
fetch(request).catch(error => {
console.warn('🌐 Network request failed:', request.url, error);
// Vermeide Fehler-Loops bei Service Worker eigenen Requests
if (request.url.includes('sw.js') || request.url.includes('service-worker')) {
throw error;
}
// Für kritische Fehler eine Fallback-Response zurückgeben
if (request.destination === 'document') {
return new Response('Service temporarily unavailable', {
status: 503,
statusText: 'Service Unavailable',
headers: { 'Content-Type': 'text/html' }
});
}
// Für API-Requests
if (request.url.includes('/api/')) {
return new Response(JSON.stringify({
success: false,
error: 'Network error',
message: 'Service temporarily unavailable'
}), {
status: 503,
statusText: 'Service Unavailable',
headers: { 'Content-Type': 'application/json' }
});
}
// Für andere Requests: Fehler weiterwerfen
throw error;
})
);
});
/**
* Cache First Strategie
* Versucht zuerst aus dem Cache zu laden, dann aus dem Netzwerk
*/
async function cacheFirst(request) {
try {
// Validierung der Anfrage
if (!request || !request.url) {
throw new Error('Ungültige Anfrage für Cache First');
}
const cache = await caches.open(STATIC_CACHE_NAME);
const cachedResponse = await cache.match(request);
if (cachedResponse && cachedResponse.ok) {
console.log('📦 Aus Cache geladen:', request.url);
return cachedResponse;
}
const networkResponse = await fetch(request);
if (networkResponse && networkResponse.ok) {
try {
await cache.put(request, networkResponse.clone());
console.log('🌐 Aus Netzwerk geladen und gecacht:', request.url);
} catch (cacheError) {
console.warn('⚠️ Cache-Speicherung fehlgeschlagen:', cacheError);
}
}
return networkResponse;
} catch (error) {
console.error('❌ Cache First Fehler:', error);
// Erweiterte Fallback-Strategien
if (request.url.includes('tailwind.min.css') || request.url.includes('.css')) {
return new Response('/* Offline CSS Fallback */', {
headers: { 'Content-Type': 'text/css' },
status: 200
});
}
if (request.url.includes('.js')) {
return new Response('// Offline JS Fallback', {
headers: { 'Content-Type': 'application/javascript' },
status: 200
});
}
// Für andere Ressourcen: Netzwerk-Error weiterwerfen
throw error;
}
}
/**
* Network First Strategie
* Versucht zuerst aus dem Netzwerk zu laden, dann aus dem Cache
*/
async function networkFirst(request) {
try {
// Validierung der Anfrage
if (!request || !request.url) {
throw new Error('Ungültige Anfrage für Network First');
}
const networkResponse = await fetch(request);
if (networkResponse && networkResponse.ok) {
try {
const cache = await caches.open(DYNAMIC_CACHE_NAME);
await cache.put(request, networkResponse.clone());
console.log('🌐 Aus Netzwerk geladen:', request.url);
} catch (cacheError) {
console.warn('⚠️ Cache-Speicherung bei Network First fehlgeschlagen:', cacheError);
}
return networkResponse;
}
throw new Error(`Network response not ok: ${networkResponse?.status || 'unknown'}`);
} catch (error) {
console.log('📦 Netzwerk nicht verfügbar, versuche Cache:', request.url);
try {
const cache = await caches.open(DYNAMIC_CACHE_NAME);
const cachedResponse = await cache.match(request);
if (cachedResponse && cachedResponse.ok) {
console.log('📦 Aus Cache geladen (Offline):', request.url);
return cachedResponse;
}
} catch (cacheError) {
console.error('❌ Cache-Zugriff fehlgeschlagen:', cacheError);
}
// Offline-Fallback für API-Requests
if (request.url.includes('/api/')) {
return new Response(JSON.stringify({
success: false,
error: 'Offline - Keine Verbindung zum Server',
offline: true
}), {
status: 503,
headers: { 'Content-Type': 'application/json' }
});
}
// Offline-Fallback für HTML-Seiten
if (request.headers.get('accept').includes('text/html')) {
const offlineHtml = `
<!DOCTYPE html>
<html>
<head>
<title>MYP - Offline</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
body { font-family: Arial, sans-serif; text-align: center; padding: 50px; }
.offline-message { max-width: 500px; margin: 0 auto; }
.icon { font-size: 64px; margin-bottom: 20px; }
</style>
</head>
<body>
<div class="offline-message">
<div class="icon">📡</div>
<h1>Offline</h1>
<p>Sie sind derzeit offline. Bitte überprüfen Sie Ihre Internetverbindung.</p>
<button onclick="window.location.reload()">Erneut versuchen</button>
</div>
</body>
</html>
`;
return new Response(offlineHtml, {
headers: { 'Content-Type': 'text/html' }
});
}
throw error;
}
}
// Background Sync für Offline-Aktionen
self.addEventListener('sync', event => {
console.log('🔄 Background Sync Event:', event.tag);
if (event.tag === 'background-sync-jobs') {
event.waitUntil(syncJobs());
}
});
/**
* Synchronisiert Jobs im Hintergrund
*/
async function syncJobs() {
try {
console.log('🔄 Synchronisiere Jobs im Hintergrund...');
// Hier könnten offline gespeicherte Aktionen synchronisiert werden
const response = await fetch('/api/jobs');
if (response.ok) {
console.log('✅ Jobs erfolgreich synchronisiert');
}
} catch (error) {
console.error('❌ Fehler bei Job-Synchronisation:', error);
}
}
// Push-Benachrichtigungen
self.addEventListener('push', event => {
console.log('📬 Push-Benachrichtigung erhalten');
const options = {
body: 'Sie haben eine neue Benachrichtigung',
icon: '/static/icons/icon-192.png',
badge: '/static/icons/icon-192.png',
vibrate: [100, 50, 100],
data: {
dateOfArrival: Date.now(),
primaryKey: 1
},
actions: [
{
action: 'explore',
title: 'Anzeigen',
icon: '/static/icons/icon-192.png'
},
{
action: 'close',
title: 'Schließen',
icon: '/static/icons/icon-192.png'
}
]
};
if (event.data) {
const data = event.data.json();
options.body = data.message || options.body;
options.title = data.title || 'MYP Benachrichtigung';
}
event.waitUntil(
self.registration.showNotification('MYP System', options)
);
});
// Benachrichtigung-Click Handler
self.addEventListener('notificationclick', event => {
console.log('🔔 Benachrichtigung geklickt:', event.action);
event.notification.close();
if (event.action === 'explore') {
event.waitUntil(
clients.openWindow('/')
);
}
});
console.log('🚀 MYP Service Worker geladen');