From 4aa711c7ae79809f280353e0c4d19fea24ffacca Mon Sep 17 00:00:00 2001 From: DJP Date: Tue, 12 May 2026 20:12:03 -0400 Subject: [PATCH] createDeliverable: fall back to org default pipeline when project has none MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If a deliverable is created on a project that has no `pipelineTemplateId`, look up the org's default `PipelineTemplate` and use its stages — mirrors the existing fallback in `createProject`. Also persists the chosen template back onto the project so future deliverables don't re-resolve and the deliverable detail UI can show "Pipeline: …". Closes the gap where a deliverable created before a pipeline was attached to its project landed with zero stages. Co-Authored-By: Claude Opus 4.7 (1M context) --- src/lib/services/deliverable-service.ts | 36 ++++++++++++++++++++++--- 1 file changed, 33 insertions(+), 3 deletions(-) diff --git a/src/lib/services/deliverable-service.ts b/src/lib/services/deliverable-service.ts index 398c4fe..dc5eb92 100644 --- a/src/lib/services/deliverable-service.ts +++ b/src/lib/services/deliverable-service.ts @@ -46,9 +46,39 @@ export async function createDeliverable( }); if (!project) throw new Error("Project not found"); - // Use dynamic pipeline stages if project has a template, else fall back to global - const useDynamic = !!project.pipelineTemplate; - const dynamicStages = project.pipelineTemplate?.stages ?? []; + // Default-pipeline fallback: if the project has no template attached, + // try the org's default PipelineTemplate before giving up to global + // PipelineStageTemplate seeds. Mirrors the behaviour of createProject. + let resolvedTemplate = project.pipelineTemplate; + if (!resolvedTemplate) { + const def = await prisma.pipelineTemplate.findFirst({ + where: { + organizationId: project.organizationId, + isDefault: true, + isArchived: false, + }, + include: { + stages: { + include: { dependsOn: true }, + orderBy: { order: "asc" }, + }, + }, + }); + if (def) { + resolvedTemplate = def; + // Persist the choice on the project so subsequent deliverables don't + // re-resolve and so the deliverable detail UI can show "Pipeline: …". + await prisma.project.update({ + where: { id: projectId }, + data: { pipelineTemplateId: def.id }, + }); + } + } + + // Use dynamic pipeline stages if project (or default fallback) has a + // template, else fall back to global PipelineStageTemplate seeds. + const useDynamic = !!resolvedTemplate; + const dynamicStages = resolvedTemplate?.stages ?? []; // Always fetch global templates (needed for templateId FK even with dynamic pipelines) const globalTemplates = await prisma.pipelineStageTemplate.findMany({