feat(T-560): SSE-route accepteert story_log-payloads

StoryLogPayload type toegevoegd aan NotifyPayload union. In de
notification-handler: idea_id-pad checkt accessibleIdeaIds (M12
user-private), fallback op product_id check accessibleProductIds.
Consistent met question-payload-pattern.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Janpeter Visser 2026-05-06 00:17:38 +02:00
parent a5f62a0323
commit e1da9aae43

View file

@ -53,7 +53,20 @@ interface IdeaJobPayload {
status: string
}
type NotifyPayload = QuestionPayload | IdeaJobPayload
// Story-log-payloads: emitted by notify_story_log_change trigger op story_logs
// (T-559). Carries product_id voor productAccessFilter en optioneel idea_id
// voor user-private idea-access (M12 keuze 2). log_type is informatief.
interface StoryLogPayload {
op: 'INSERT'
entity: 'story_log'
id: string
story_id: string
product_id: string | null
idea_id: string | null
log_type: 'IMPLEMENTATION_PLAN' | 'COMMIT' | 'TEST_RESULT' | string
}
type NotifyPayload = QuestionPayload | IdeaJobPayload | StoryLogPayload
function isQuestionPayload(p: NotifyPayload): p is QuestionPayload {
return 'entity' in p && p.entity === 'question'
@ -69,6 +82,10 @@ function isIdeaJobPayload(p: NotifyPayload): p is IdeaJobPayload {
)
}
function isStoryLogPayload(p: NotifyPayload): p is StoryLogPayload {
return 'entity' in p && p.entity === 'story_log'
}
export async function GET(request: NextRequest) {
const session = await getSession()
if (!session.userId) {
@ -164,6 +181,21 @@ export async function GET(request: NextRequest) {
return
}
if (isStoryLogPayload(payload)) {
// Sync-tab (PBI-36 ST-1219): story_log-event moet door als óf de
// story bij een user-eigen idee hoort, óf de user productAccess
// heeft (voor non-Idea views). idea_id-pad heeft voorrang —
// sluit aan op M12 strikt user_id-only voor ideas.
if (payload.idea_id && accessibleIdeaIds.has(payload.idea_id)) {
enqueue(`data: ${msg.payload}\n\n`)
return
}
if (payload.product_id && accessibleProductIds.has(payload.product_id)) {
enqueue(`data: ${msg.payload}\n\n`)
}
return
}
if (!isQuestionPayload(payload)) return
// Idea-question: alleen voor de eigenaar van het idee.