Skip to content

PEA-2234 Review Notes — DELETE BEFORE MERGE

Temporary review aid. Delete this file before merging the PR into staging. Linear: PEA-2234 Companion frontend PR must ship in the same deploy (atomic FE+BE).


What this changes (feature-level)

Before: Collaborative Studio events (credits, activities, workbench shot/scene/asset/batch updates) were fanned out per user:

  1. Query ProjectsModel.getProjectParticipantUserIds(projectId)
  2. Loop and JaduSpinePublisher.publish(userId, FrontendChannels.STUDIO, …) for each participant

After: One publish to a project-level Centrifugo channel:

  • Backend: JaduSpinePublisher.publishToProject(projectId, …)CustomChannel(projectId)custom:<projectId>
  • Frontend: useProjectChannel(projectId, handler) subscribes all collaborators on that project

User-visible behavior: Collaborators in the same project should see realtime updates (shot gen, scene updates, asset updates, credit balance, activity feed) without each needing a personal fan-out. Personal tools (standalone asset gen, guru chats) are unchanged.


Backend changes (this repo)

1. src/shared/jaduSpine.publisher.ts

  • Added publishToProject(projectId, event, status, message, isSuccess, data, extraPayloadFields?).
  • Uses new CustomChannel(projectId) (not FrontendChannel).
  • Same SpineMessage envelope as user publish (topic + data with event, status, isSuccess, message, data, timestamp).
  • Same error handling / non-throwing resilience as publish.
  • Empty projectId guard: if !projectId, logs JaduSpine project publish skipped: missing projectId and returns (avoids publishing to custom:).

2. src/credits/credits.publisher.ts

  • Removed getProjectParticipantUserIds + per-user loop.
  • Single publishToProject(payload.projectId, PROJECT_CREDIT_EVENTS.BALANCE_UPDATED, …).

3. src/projectActivities/projectActivities.service.ts

  • Removed participant fan-out loop.
  • publishActivityEvent → single publishToProject(projectId, topic, …) for created/updated activity events.

4. src/webhooks/webhooks.service.ts

  • When job.projectLinks present → publishToProject for ASSET_UPDATED (and asset image status path).
  • When no project context → still publish to user channel (ASSET_GEN_RESPONSE / fallbacks).
  • Pre-existing branch: storyLinks without projectLinks still publishes SCENE_UPDATED / SHOT_UPDATED on user channel (no project to target).
  • QC follow-up now passes job.projectLinks?.projectId into runQualityCheckAsync.

5. src/workbench/workbench.service.ts + workbench.controller.ts

  • Shot image / batch / video / sequence video success & failure publishes switched to publishToProject.
  • projectId threaded through async method signatures; controller passes projectId ?? '' or job.projectLinks?.projectId ?? '' (empty guarded in publisher).
  • All workbench runQualityCheckAsync call sites now pass projectId as 4th arg.

6. src/assetGen/assetGen.service.ts

  • Added private publishQualityCheckEvent(…, projectId?):
  • with projectIdpublishToProject
  • without → user publish (standalone asset gen)
  • runQualityCheckAsync(userId, jobId, eventName, projectId?) — optional 4th arg.
  • runPromptRewriteAsync(job, eventName, projectId?) — same, so rewrite events stay on the same channel as QC.
  • Standalone runAssetGenerationAsync still calls QC without projectId (user channel).

7. Tests

  • tests/shared/jaduSpine.publisher.test.ts — mock CustomChannel; cases for project publish, empty-id skip, error logging.
  • tests/webhooks/webhooks.service.test.ts — mock publishToProject; assert user-channel path + project ASSET_UPDATED path; QC called with undefined projectId when no links.
  • tests/assetGen/assetGen.service.test.ts — rewrite spy expects 3rd arg; new test that QC with projectId uses publishToProject only.
  • tests/credits/credits.service.test.ts — mock + assert publishToProject instead of publish.

Not changed in backend (intentional)

  • getProjectParticipantUserIds still exists on ProjectsModel but is @deprecated — unused for publishing after PEA-2234.
  • Guru chat publishers, pose maker guru, standalone asset gen completion → user channel.
  • Minimatics routes/publishers → out of scope (skipped entirely).
  • Legacy Socket.IO paths already @deprecated (webhookSocketFollowUp, run*WithSocket, etc.) — left in place, not removed.
  • Centrifugo custom namespace config → DevOps / infra, not in this repo. Must have allow_subscribe_for_client: true or FE subscriptions fail silently.

Frontend changes (companion repo studio-frontend)

New: app/_hooks/useProjectChannel.ts

  • Subscribes via CustomChannel(projectId) using _subscribeToChannel / _onChannelMessage.
  • No-ops when projectId is undefined/empty.
  • Cleanup unsubscribes on unmount / projectId change.

Migrated listeners to project channel

File Events
useWorkbench.ts shotUpdated, sceneUpdated, assetUpdated, shotImageBatchSlotUpdated, assetGenQualityCheckResponse
useProjectActivityPanel.ts activity created/updated + credit balance
useEntityActivities.ts activity created/updated
useAssetDetailModal.ts assetUpdated

Critical wiring fix (would have shipped broken without this)

useWorkbenchHook accepted projectId but no callers passed it. All six call sites now pass it:

File projectId source
useShot.ts projectId ?? story?.projectId
useProjectEpisodeExtended.ts story?.projectId
useEpisodeJaduCutView.ts story?.projectId
useEpisodeAsset.ts projectId ?? project?.projectId
_assets.tsx projectId \|\| project?.projectId
_workbench.tsx story?.projectId

Unchanged on frontend (intentional)

  • useAssetGen.ts, useGuruChat.ts, shot-image-edit / sketch / pose guru hooks → still user channel via useJaduSpine().onMessage.
  • Minimatics → skipped.

What we skipped / out of scope

  1. Minimatics — separate app / FrontendChannels.MINIMATICS; not touched.
  2. Centrifugo namespace config — confirm with DevOps before deploy.
  3. Removing unused getProjectParticipantUserIds — marked @deprecated, not deleted (can remove in a follow-up).
  4. Legacy Socket.IO cleanup — methods already @deprecated; full removal not part of this ticket.
  5. Lockfile-only noise — not committed.

Credits README realtime section was updated in this follow-up commit.


Deploy / review checklist

  • [ ] Ship backend + frontend PRs together (same release). Partial deploy breaks workbench realtime.
  • [ ] Confirm Centrifugo custom namespace allows client subscribe.
  • [ ] Manual QA: two collaborator tabs on same project → generate shot in A → B updates live.
  • [ ] Manual QA: standalone Asset Gen tool still only notifies the generating user.
  • [ ] Delete this file (PEA-2234-REVIEW.md) before merge.

Suggested test commands

# backend
cd studio-backend && npm test -- --run tests/shared/jaduSpine.publisher.test.ts tests/webhooks/webhooks.service.test.ts tests/assetGen/assetGen.service.test.ts tests/credits/credits.service.test.ts