From 404daa081ebf0f8704db2860f0178447311d749f Mon Sep 17 00:00:00 2001 From: twotalesanimation <80506065+twotalesanimation@users.noreply.github.com> Date: Sat, 1 Aug 2026 17:51:33 +0200 Subject: [PATCH] oops2 --- app/(dashboard)/projects/page.tsx | 7 +- lib/render-pipeline/exports.ts | 56 ++++-- .../migration.sql | 175 ++++++++++++++++++ 3 files changed, 221 insertions(+), 17 deletions(-) create mode 100644 prisma/migrations/20260801000000_add_render_pipeline_phase1/migration.sql diff --git a/app/(dashboard)/projects/page.tsx b/app/(dashboard)/projects/page.tsx index 4db701e..244a9e5 100644 --- a/app/(dashboard)/projects/page.tsx +++ b/app/(dashboard)/projects/page.tsx @@ -12,7 +12,7 @@ export default function ProjectsPage() { const [search, setSearch] = useState(""); const [showNew, setShowNew] = useState(false); - const { data, isLoading } = useQuery({ + const { data, isLoading, isError } = useQuery({ queryKey: ["projects", search], queryFn: async () => { const res = await fetch(`/api/projects?q=${encodeURIComponent(search)}`); @@ -80,6 +80,11 @@ export default function ProjectsPage() {
Could not load projects.
+Check server logs and database connectivity, then refresh.
+No projects found.
diff --git a/lib/render-pipeline/exports.ts b/lib/render-pipeline/exports.ts index 3b272e5..ad10b54 100644 --- a/lib/render-pipeline/exports.ts +++ b/lib/render-pipeline/exports.ts @@ -2,6 +2,13 @@ import { z } from "zod"; import { db } from "@/lib/db"; import { Prisma } from "@prisma/client"; +function isPrismaTableOrColumnMissingError(error: unknown): boolean { + if (error instanceof Prisma.PrismaClientKnownRequestError) { + return error.code === "P2021" || error.code === "P2022"; + } + return false; +} + const exportManifestSchema = z.object({ shotCode: z.string().min(1), projectCode: z.string().min(1), @@ -152,23 +159,40 @@ export async function createRenderExport(input: { } export async function listExportsForQueue() { - return db.export.findMany({ - where: { status: { notIn: ["SUPERSEDED", "ARCHIVED", "CANCELLED", "DELIVERED"] } }, - orderBy: [{ createdAt: "desc" }], - include: { - shot: { select: { shotCode: true, shotVersion: true, project: { select: { code: true } } } }, - renderJobs: { orderBy: [{ createdAt: "desc" }], take: 1 }, - }, - }); + try { + return await db.export.findMany({ + where: { status: { notIn: ["SUPERSEDED", "ARCHIVED", "CANCELLED", "DELIVERED"] } }, + orderBy: [{ createdAt: "desc" }], + include: { + shot: { select: { shotCode: true, shotVersion: true, project: { select: { code: true } } } }, + renderJobs: { orderBy: [{ createdAt: "desc" }], take: 1 }, + }, + }); + } catch (error) { + // Render pipeline tables may not exist yet if Phase 1 migrations have not been applied. + if (isPrismaTableOrColumnMissingError(error)) { + return []; + } + + throw error; + } } export async function getLatestExportForShot(shotId: string) { - return db.export.findFirst({ - where: { shotId }, - orderBy: [{ createdAt: "desc" }], - include: { - shot: { select: { shotCode: true, project: { select: { code: true } } } }, - renderJobs: { orderBy: [{ createdAt: "desc" }], take: 1 }, - }, - }); + try { + return await db.export.findFirst({ + where: { shotId }, + orderBy: [{ createdAt: "desc" }], + include: { + shot: { select: { shotCode: true, project: { select: { code: true } } } }, + renderJobs: { orderBy: [{ createdAt: "desc" }], take: 1 }, + }, + }); + } catch (error) { + if (isPrismaTableOrColumnMissingError(error)) { + return null; + } + + throw error; + } } diff --git a/prisma/migrations/20260801000000_add_render_pipeline_phase1/migration.sql b/prisma/migrations/20260801000000_add_render_pipeline_phase1/migration.sql new file mode 100644 index 0000000..ebe329f --- /dev/null +++ b/prisma/migrations/20260801000000_add_render_pipeline_phase1/migration.sql @@ -0,0 +1,175 @@ +-- CreateEnum +DO $$ BEGIN + CREATE TYPE "ExportStatus" AS ENUM ( + 'QUEUED', + 'RENDERING', + 'RENDER_FAILED', + 'VALIDATING', + 'VALIDATION_FAILED', + 'GENERATING_PREVIEW', + 'PREVIEW_FAILED', + 'READY_FOR_QC', + 'QC_FAILED', + 'READY_FOR_DELIVERY', + 'PACKAGED', + 'DELIVERED', + 'SUPERSEDED', + 'ARCHIVED', + 'CANCELLED' + ); +EXCEPTION + WHEN duplicate_object THEN null; +END $$; + +-- CreateEnum +DO $$ BEGIN + CREATE TYPE "RenderJobStatus" AS ENUM ( + 'QUEUED', + 'CLAIMED', + 'RUNNING', + 'COMPLETED', + 'FAILED', + 'CANCELLED', + 'EXPIRED' + ); +EXCEPTION + WHEN duplicate_object THEN null; +END $$; + +-- CreateEnum +DO $$ BEGIN + CREATE TYPE "RenderJobType" AS ENUM ( + 'AE_RENDER', + 'PREVIEW_ONLY', + 'DELIVERY_BUILD' + ); +EXCEPTION + WHEN duplicate_object THEN null; +END $$; + +-- CreateTable +CREATE TABLE IF NOT EXISTS "exports" ( + "id" TEXT NOT NULL, + "shotId" TEXT NOT NULL, + "projectId" TEXT NOT NULL, + "taskId" TEXT, + "versionId" TEXT, + "versionNumber" INTEGER NOT NULL, + "versionString" TEXT NOT NULL, + "status" "ExportStatus" NOT NULL DEFAULT 'QUEUED', + "statusChangedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "aepPath" TEXT NOT NULL, + "compName" TEXT NOT NULL, + "rendererType" TEXT NOT NULL, + "outputDir" TEXT NOT NULL, + "outputPattern" TEXT NOT NULL, + "frameStart" INTEGER NOT NULL, + "frameEnd" INTEGER NOT NULL, + "fps" DOUBLE PRECISION NOT NULL, + "width" INTEGER NOT NULL, + "height" INTEGER NOT NULL, + "colorspace" TEXT, + "deliveryMovPath" TEXT, + "previewMovKey" TEXT, + "thumbnailKey" TEXT, + "metadataKey" TEXT, + "exrFileCount" INTEGER, + "exrTotalBytes" BIGINT, + "checksum" TEXT, + "submittedById" TEXT, + "submittedByName" TEXT, + "supersededById" TEXT, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "exports_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE IF NOT EXISTS "render_jobs" ( + "id" TEXT NOT NULL, + "type" "RenderJobType" NOT NULL DEFAULT 'AE_RENDER', + "exportId" TEXT, + "deliveryId" TEXT, + "attempt" INTEGER NOT NULL DEFAULT 1, + "maxAttempts" INTEGER NOT NULL DEFAULT 3, + "status" "RenderJobStatus" NOT NULL DEFAULT 'QUEUED', + "priority" INTEGER NOT NULL DEFAULT 50, + "manifest" JSONB NOT NULL, + "machineId" TEXT, + "claimedAt" TIMESTAMP(3), + "leaseExpiresAt" TIMESTAMP(3), + "startedAt" TIMESTAMP(3), + "finishedAt" TIMESTAMP(3), + "progress" DOUBLE PRECISION NOT NULL DEFAULT 0, + "currentFrame" INTEGER, + "totalFrames" INTEGER, + "etaSeconds" INTEGER, + "exitCode" INTEGER, + "errorMessage" TEXT, + "logTail" TEXT, + "logFileKey" TEXT, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "render_jobs_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE IF NOT EXISTS "export_events" ( + "id" TEXT NOT NULL, + "exportId" TEXT NOT NULL, + "fromStatus" TEXT, + "toStatus" TEXT NOT NULL, + "actorType" TEXT NOT NULL, + "actorId" TEXT, + "note" TEXT, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "export_events_pkey" PRIMARY KEY ("id") +); + +-- CreateIndex +CREATE UNIQUE INDEX IF NOT EXISTS "exports_shotId_versionNumber_key" ON "exports"("shotId", "versionNumber"); + +-- CreateIndex +CREATE INDEX IF NOT EXISTS "exports_status_idx" ON "exports"("status"); + +-- CreateIndex +CREATE INDEX IF NOT EXISTS "exports_projectId_status_idx" ON "exports"("projectId", "status"); + +-- CreateIndex +CREATE INDEX IF NOT EXISTS "render_jobs_status_priority_createdAt_idx" ON "render_jobs"("status", "priority", "createdAt"); + +-- CreateIndex +CREATE INDEX IF NOT EXISTS "export_events_exportId_createdAt_idx" ON "export_events"("exportId", "createdAt"); + +-- AddForeignKey +DO $$ BEGIN + ALTER TABLE "exports" + ADD CONSTRAINT "exports_shotId_fkey" + FOREIGN KEY ("shotId") REFERENCES "shots"("id") + ON DELETE CASCADE ON UPDATE CASCADE; +EXCEPTION + WHEN duplicate_object THEN null; +END $$; + +-- AddForeignKey +DO $$ BEGIN + ALTER TABLE "render_jobs" + ADD CONSTRAINT "render_jobs_exportId_fkey" + FOREIGN KEY ("exportId") REFERENCES "exports"("id") + ON DELETE CASCADE ON UPDATE CASCADE; +EXCEPTION + WHEN duplicate_object THEN null; +END $$; + +-- AddForeignKey +DO $$ BEGIN + ALTER TABLE "export_events" + ADD CONSTRAINT "export_events_exportId_fkey" + FOREIGN KEY ("exportId") REFERENCES "exports"("id") + ON DELETE CASCADE ON UPDATE CASCADE; +EXCEPTION + WHEN duplicate_object THEN null; +END $$;