diff --git a/app/api/curator/specials/[id]/route.ts b/app/api/curator/specials/[id]/route.ts index da6e1e9..666289e 100644 --- a/app/api/curator/specials/[id]/route.ts +++ b/app/api/curator/specials/[id]/route.ts @@ -1,9 +1,14 @@ import { NextRequest, NextResponse } from 'next/server'; import { PrismaClient } from '@prisma/client'; import { requireStaffAuth } from '@/lib/auth'; +import { access } from 'fs/promises'; +import path from 'path'; const prisma = new PrismaClient(); +// Mark route as dynamic to prevent caching +export const dynamic = 'force-dynamic'; + export async function GET( request: NextRequest, { params }: { params: Promise<{ id: string }> } @@ -52,13 +57,40 @@ export async function GET( return NextResponse.json({ error: 'Special not found' }, { status: 404 }); } - // Filtere Songs ohne vollständige Song-Daten (song, song.filename) - // Dies verhindert Fehler im Frontend, wenn Songs gelöscht wurden oder Daten fehlen - const filteredSongs = special.songs.filter(ss => ss.song && ss.song.filename); + // Filtere Songs ohne vollständige Song-Daten und prüfe Datei-Existenz + // Dies verhindert Fehler im Frontend, wenn Songs gelöscht wurden, Daten fehlen + // oder Dateien noch nicht im Container verfügbar sind (Volume Mount Delay) + const uploadsDir = path.join(process.cwd(), 'public/uploads'); + + const filteredSongs = await Promise.all( + special.songs + .filter(ss => ss.song && ss.song.filename) + .map(async (ss) => { + const filePath = path.join(uploadsDir, ss.song.filename); + try { + // Prüfe ob Datei existiert und zugänglich ist + await access(filePath); + return ss; + } catch (error) { + // Datei existiert nicht oder ist nicht zugänglich + console.warn(`[API] Song file not available: ${ss.song.filename} (may be syncing)`); + return null; + } + }) + ); + + // Entferne null-Werte (Songs ohne verfügbare Dateien) + const availableSongs = filteredSongs.filter((ss): ss is typeof special.songs[0] => ss !== null); return NextResponse.json({ ...special, - songs: filteredSongs, + songs: availableSongs, + }, { + headers: { + 'Cache-Control': 'no-store, no-cache, must-revalidate, proxy-revalidate', + 'Pragma': 'no-cache', + 'Expires': '0', + }, }); } diff --git a/app/curator/specials/[id]/page.tsx b/app/curator/specials/[id]/page.tsx index 686ed7d..e8d7386 100644 --- a/app/curator/specials/[id]/page.tsx +++ b/app/curator/specials/[id]/page.tsx @@ -32,6 +32,7 @@ export default function CuratorSpecialEditorPage() { } const res = await fetch(`/api/curator/specials/${specialId}`, { headers: getCuratorAuthHeaders(), + cache: 'no-store', }); if (res.status === 403) { setError(t('specialForbidden'));