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:
- Query
ProjectsModel.getProjectParticipantUserIds(projectId) - 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)(notFrontendChannel). - Same SpineMessage envelope as user
publish(topic+datawithevent,status,isSuccess,message,data,timestamp). - Same error handling / non-throwing resilience as
publish. - Empty
projectIdguard: if!projectId, logsJaduSpine project publish skipped: missing projectIdand returns (avoids publishing tocustom:).
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→ singlepublishToProject(projectId, topic, …)for created/updated activity events.
4. src/webhooks/webhooks.service.ts¶
- When
job.projectLinkspresent →publishToProjectforASSET_UPDATED(and asset image status path). - When no project context → still
publishto user channel (ASSET_GEN_RESPONSE/ fallbacks). - Pre-existing branch:
storyLinkswithoutprojectLinksstill publishesSCENE_UPDATED/SHOT_UPDATEDon user channel (no project to target). - QC follow-up now passes
job.projectLinks?.projectIdintorunQualityCheckAsync.
5. src/workbench/workbench.service.ts + workbench.controller.ts¶
- Shot image / batch / video / sequence video success & failure publishes switched to
publishToProject. projectIdthreaded through async method signatures; controller passesprojectId ?? ''orjob.projectLinks?.projectId ?? ''(empty guarded in publisher).- All workbench
runQualityCheckAsynccall sites now passprojectIdas 4th arg.
6. src/assetGen/assetGen.service.ts¶
- Added private
publishQualityCheckEvent(…, projectId?): - with
projectId→publishToProject - 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
runAssetGenerationAsyncstill calls QC withoutprojectId(user channel).
7. Tests¶
tests/shared/jaduSpine.publisher.test.ts— mockCustomChannel; cases for project publish, empty-id skip, error logging.tests/webhooks/webhooks.service.test.ts— mockpublishToProject; assert user-channel path + projectASSET_UPDATEDpath; QC called withundefinedprojectId when no links.tests/assetGen/assetGen.service.test.ts— rewrite spy expects 3rd arg; new test that QC withprojectIdusespublishToProjectonly.tests/credits/credits.service.test.ts— mock + assertpublishToProjectinstead ofpublish.
Not changed in backend (intentional)¶
getProjectParticipantUserIdsstill exists onProjectsModelbut 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
customnamespace config → DevOps / infra, not in this repo. Must haveallow_subscribe_for_client: trueor 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
projectIdis 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 viauseJaduSpine().onMessage.- Minimatics → skipped.
What we skipped / out of scope¶
- Minimatics — separate app /
FrontendChannels.MINIMATICS; not touched. - Centrifugo namespace config — confirm with DevOps before deploy.
- Removing unused
getProjectParticipantUserIds— marked@deprecated, not deleted (can remove in a follow-up). - Legacy Socket.IO cleanup — methods already
@deprecated; full removal not part of this ticket. - 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
customnamespace 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