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