feat(T-561): loadIdeaSyncData server-loader voor Sync-tab
Joint Idea → PBI → Stories → Tasks → ClaudeJobs + StoryLog in één prisma.findFirst-call. user_id-scope conform M12-keuze 2 (strikt user_id-only). Filtert ClaudeJob op kind=TASK_IMPLEMENTATION en neemt laatste 20 story-logs per story. Returns null als idea geen pbi_id heeft — caller render geen tab. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
e1da9aae43
commit
f4f02bd0d2
1 changed files with 85 additions and 0 deletions
85
app/(app)/ideas/[id]/sync-tab-server.ts
Normal file
85
app/(app)/ideas/[id]/sync-tab-server.ts
Normal file
|
|
@ -0,0 +1,85 @@
|
||||||
|
import 'server-only'
|
||||||
|
import { prisma } from '@/lib/prisma'
|
||||||
|
|
||||||
|
// Server-only loader voor de Sync-tab op /ideas/[id].
|
||||||
|
// Joint Idea → PBI → Stories → Tasks → ClaudeJobs + StoryLog.
|
||||||
|
// Auth-scope: strikt user_id-only conform M12-keuze 2.
|
||||||
|
//
|
||||||
|
// Returns null wanneer:
|
||||||
|
// - idea bestaat niet of behoort niet aan user
|
||||||
|
// - idea heeft geen pbi_id (status !== PLANNED, dus sync-tab niet relevant)
|
||||||
|
//
|
||||||
|
// Caller (page.tsx) moet de tab niet renderen als deze null retourneert.
|
||||||
|
export async function loadIdeaSyncData(ideaId: string, userId: string) {
|
||||||
|
const idea = await prisma.idea.findFirst({
|
||||||
|
where: { id: ideaId, user_id: userId },
|
||||||
|
select: {
|
||||||
|
id: true,
|
||||||
|
code: true,
|
||||||
|
title: true,
|
||||||
|
status: true,
|
||||||
|
pbi_id: true,
|
||||||
|
product: { select: { id: true, name: true, repo_url: true } },
|
||||||
|
pbi: {
|
||||||
|
select: {
|
||||||
|
id: true,
|
||||||
|
code: true,
|
||||||
|
title: true,
|
||||||
|
pr_url: true,
|
||||||
|
pr_merged_at: true,
|
||||||
|
stories: {
|
||||||
|
orderBy: { sort_order: 'asc' },
|
||||||
|
select: {
|
||||||
|
id: true,
|
||||||
|
code: true,
|
||||||
|
title: true,
|
||||||
|
status: true,
|
||||||
|
tasks: {
|
||||||
|
orderBy: { sort_order: 'asc' },
|
||||||
|
select: {
|
||||||
|
id: true,
|
||||||
|
code: true,
|
||||||
|
title: true,
|
||||||
|
status: true,
|
||||||
|
claude_jobs: {
|
||||||
|
where: { kind: 'TASK_IMPLEMENTATION' },
|
||||||
|
orderBy: { created_at: 'desc' },
|
||||||
|
select: {
|
||||||
|
id: true,
|
||||||
|
status: true,
|
||||||
|
branch: true,
|
||||||
|
pushed_at: true,
|
||||||
|
pr_url: true,
|
||||||
|
error: true,
|
||||||
|
summary: true,
|
||||||
|
created_at: true,
|
||||||
|
finished_at: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
logs: {
|
||||||
|
orderBy: { created_at: 'desc' },
|
||||||
|
take: 20,
|
||||||
|
select: {
|
||||||
|
id: true,
|
||||||
|
type: true,
|
||||||
|
content: true,
|
||||||
|
status: true,
|
||||||
|
commit_hash: true,
|
||||||
|
commit_message: true,
|
||||||
|
created_at: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
if (!idea || !idea.pbi) return null
|
||||||
|
return idea
|
||||||
|
}
|
||||||
|
|
||||||
|
export type IdeaSyncData = NonNullable<Awaited<ReturnType<typeof loadIdeaSyncData>>>
|
||||||
Loading…
Add table
Add a link
Reference in a new issue