From a10ccc936e1df50b202bd1e88e6ef833ca6e26ff Mon Sep 17 00:00:00 2001 From: Madhura68 Date: Wed, 29 Apr 2026 17:10:56 +0200 Subject: [PATCH] feat(ST-1109.5): auto-mark PBI as DONE when all its stories are DONE on sprint close MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Extends completeSprintAction's $transaction with PBI status cascade: - Pre-transaction: identify PBIs touched by this close (via stories.pbi_id), fetch each with all its stories - Skip PBIs already DONE; skip PBIs with 0 stories - Mark PBI DONE only when every story (post-decision) is DONE — stories outside the sprint are evaluated against their current DB status - Promote-only: never demotes a PBI that becomes "incomplete" again Co-Authored-By: Claude Opus 4.7 (1M context) --- actions/sprints.ts | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/actions/sprints.ts b/actions/sprints.ts index ed8857d..7eb7229 100644 --- a/actions/sprints.ts +++ b/actions/sprints.ts @@ -171,10 +171,28 @@ export async function completeSprintAction( const stories = await prisma.story.findMany({ where: { id: { in: storyIds }, sprint_id: sprintId, product_id: sprint.product_id }, - select: { id: true }, + select: { id: true, pbi_id: true }, }) if (stories.length !== storyIds.length) return { error: 'Ongeldige Sprint-afronding' } + const affectedPbiIds = [...new Set(stories.map((s) => s.pbi_id))] + const candidatePbis = await prisma.pbi.findMany({ + where: { id: { in: affectedPbiIds }, status: { not: 'DONE' } }, + select: { id: true, stories: { select: { id: true, status: true } } }, + }) + + const decisionByStoryId = new Map(entries) + const pbiIdsToMarkDone = candidatePbis + .filter( + (pbi) => + pbi.stories.length > 0 && + pbi.stories.every((s) => { + const next = decisionByStoryId.get(s.id) ?? s.status + return next === 'DONE' + }) + ) + .map((p) => p.id) + await prisma.$transaction([ ...entries.map(([storyId, status]) => prisma.story.update({ @@ -185,6 +203,9 @@ export async function completeSprintAction( }, }) ), + ...pbiIdsToMarkDone.map((id) => + prisma.pbi.update({ where: { id }, data: { status: 'DONE' } }) + ), prisma.sprint.update({ where: { id: sprintId }, data: { status: 'COMPLETED', completed_at: new Date() },