From d045b24c85eef42ce0d0dcbf0ca19a3a2990f436 Mon Sep 17 00:00:00 2001 From: ayrisdev Date: Wed, 2 Sep 2026 14:03:54 +0300 Subject: [PATCH] =?UTF-8?q?fix:=20silme=20fonksiyonlar=C4=B1nda=20ShortVid?= =?UTF-8?q?eo=20FK=20ihlali=20(kanal/segment/candidate=20sil=20hata=20veri?= =?UTF-8?q?yordu)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Faz 2'de ShortVideo eklenirken deleteRawSegment/deleteCandidateSegment/ deleteChannel güncellenmemiş — candidate_id FK'sı yüzünden bir short'u olan candidate silinmeye çalışılınca Postgres reddediyordu. Şimdi her üç yol da candidate'leri silmeden önce ilişkili ShortVideo satırlarını (+ render edilmiş dosyalarını) temizliyor. Co-Authored-By: Claude Sonnet 5 --- apps/frontend/app/actions.ts | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/apps/frontend/app/actions.ts b/apps/frontend/app/actions.ts index b7580a4..f90371c 100644 --- a/apps/frontend/app/actions.ts +++ b/apps/frontend/app/actions.ts @@ -22,10 +22,22 @@ export async function addChannel(formData: FormData) { revalidatePath("/"); } +/** ShortVideo has a required FK to CandidateSegment (candidate_id) — every deletion path that removes candidates must clear their shorts (row + rendered file) first, or Postgres rejects the candidate delete. */ +async function deleteShortsForCandidates(candidateIds: string[]): Promise { + if (candidateIds.length === 0) return; + const shorts = await prisma.shortVideo.findMany({ where: { candidateId: { in: candidateIds } } }); + await prisma.shortVideo.deleteMany({ where: { candidateId: { in: candidateIds } } }); + await Promise.all(shorts.filter((s) => s.filePath).map((s) => unlink(s.filePath!).catch(() => {}))); +} + export async function deleteRawSegment(segmentId: string) { - const segment = await prisma.rawSegment.findUnique({ where: { id: segmentId } }); + const segment = await prisma.rawSegment.findUnique({ + where: { id: segmentId }, + include: { candidates: true }, + }); if (!segment) return; + await deleteShortsForCandidates(segment.candidates.map((c) => c.id)); await prisma.candidateSegment.deleteMany({ where: { rawSegmentId: segmentId } }); await prisma.rawSegment.delete({ where: { id: segmentId } }); await unlink(segment.filePath).catch(() => {}); @@ -35,6 +47,7 @@ export async function deleteRawSegment(segmentId: string) { } export async function deleteCandidateSegment(candidateId: string) { + await deleteShortsForCandidates([candidateId]); await prisma.candidateSegment.delete({ where: { id: candidateId } }); revalidatePath("/segments"); @@ -44,11 +57,13 @@ export async function deleteCandidateSegment(candidateId: string) { export async function deleteChannel(channelId: string) { const sessions = await prisma.streamSession.findMany({ where: { channelId }, - include: { segments: true }, + include: { segments: { include: { candidates: true } } }, }); const rawSegmentIds = sessions.flatMap((s) => s.segments.map((seg) => seg.id)); + const candidateIds = sessions.flatMap((s) => s.segments.flatMap((seg) => seg.candidates.map((c) => c.id))); const filePaths = sessions.flatMap((s) => s.segments.map((seg) => seg.filePath)); + await deleteShortsForCandidates(candidateIds); await prisma.candidateSegment.deleteMany({ where: { rawSegmentId: { in: rawSegmentIds } } }); await prisma.rawSegment.deleteMany({ where: { sessionId: { in: sessions.map((s) => s.id) } } }); await prisma.streamSession.deleteMany({ where: { channelId } });