Skip to content

feat: add customizable field to journey, and journey customizable service#8813

Open
jianwei1 wants to merge 26 commits intomainfrom
jianweichong/nes-1400-backend-auto-detect-journeycustomizable-via-recalculation
Open

feat: add customizable field to journey, and journey customizable service#8813
jianwei1 wants to merge 26 commits intomainfrom
jianweichong/nes-1400-backend-auto-detect-journeycustomizable-via-recalculation

Conversation

@jianwei1
Copy link
Contributor

@jianwei1 jianwei1 commented Mar 5, 2026

Summary by CodeRabbit

  • New Features

    • Added a Journey "customizable" flag and a service to detect/sync customizable content (text, links, media) and to preserve/reset it during duplication/templating.
  • Behavior

    • Recalculation now runs after edits, duplicates, restores, order changes and template/website updates to keep the flag in sync.
  • Database

    • Added customizable column to journeys.
  • Tests

    • Expanded coverage for detection logic, propagation, and recalculation.
  • Documentation

    • Added guidance/guardrails for maintaining recalculation consistency when adding customizable fields.

jianwei1 added 13 commits March 2, 2026 20:11
…logic

- Introduced JourneyCustomizableService to handle the recalculation of the `customizable` field for journeys based on various conditions.
- Updated JourneyModule to include JourneyCustomizableService as a provider and export it for use in other modules.
- Added unit tests for JourneyCustomizableService to ensure correct functionality of the customization logic.
…ney recalculation

- Added JourneyCustomizableService to BlockResolver and BlockService to handle journey recalculations after block duplication, restoration, and updates.
- Updated unit tests to verify that recalculation is triggered appropriately in various scenarios.
- Enhanced Block module imports to include JourneyModule for better integration.
…omizableService integration

- Integrated JourneyCustomizableService into JourneyResolver to trigger recalculations based on journey updates, specifically when the website field is modified.
- Updated JourneyCustomizationFieldResolver to call recalculate after publisher updates.
- Added unit tests to ensure the correct invocation of recalculate in various scenarios, enhancing the overall functionality and reliability of journey customization features.
- Introduced new documentation for adding customizable fields to block and action types, outlining necessary updates to the JourneyCustomizableService and BlockService.
- Created a customizable-blocks.md file detailing the paths affected and the required logic updates for recalculation.
- Added a corresponding customizable-blocks.mdc file to serve as a guardrail for developers, ensuring compliance with the new customization requirements.
@jianwei1 jianwei1 self-assigned this Mar 5, 2026
@linear
Copy link

linear bot commented Mar 5, 2026

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 5, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Adds a Journey.customizable flag (Prisma + migration + GraphQL), implements JourneyCustomizableService.recalculate(journeyId) to derive and persist the flag from journey fields, blocks, actions and media, and wires recalculation calls across journey, block, and customization-field mutation paths with tests and guardrail docs.

Changes

Cohort / File(s) Summary
Docs & Guardrails
\.claude/rules/backend/customizable-blocks.md, \.cursor/rules/customizable-blocks.mdc
New guidance and guardrail files requiring updates to JourneyCustomizableService.recalculate() when adding customizable fields and mandating recalculate() calls if block update flows bypass BlockService.update().
Prisma Schema & Migration
libs/prisma/journeys/db/schema.prisma, libs/prisma/journeys/db/migrations/.../migration.sql
Adds optional Boolean customizable (default false) to the Journey model and migration to add the DB column.
GraphQL Schema Updates
apis/api-gateway/schema.graphql, apis/api-journeys-modern/schema.graphql, apis/api-journeys/schema.graphql, apis/api-journeys/src/app/modules/journey/journey.graphql
Adds customizable: Boolean to Journey and customizable: Boolean to JourneyUpdateInput across gateway and service GraphQL schemas.
New Service & Tests
apis/api-journeys/src/app/modules/journey/journeyCustomizable.service.ts, .../journeyCustomizable.service.spec.ts
Introduces JourneyCustomizableService.recalculate(journeyId) that computes hasEditableText/links/media and updates journey.customizable; extensive unit tests covering multiple block/action scenarios.
Journey Module & Resolver
apis/api-journeys/src/app/modules/journey/journey.module.ts, .../journey.resolver.ts, .../journey.resolver.spec.ts
Registers JourneyCustomizableService; resolver flows (duplicate, template, update) include/propagate customizable and invoke recalculate after relevant mutations; tests updated to assert behavior.
Block Module, Service & Resolvers
apis/api-journeys/src/app/modules/block/block.module.ts, .../block.service.ts, .../block.resolver.ts, .../*.spec.ts, .../videoTrigger/videoTrigger.resolver.spec.ts
Injects JourneyCustomizableService into block-related modules; ensures recalculate runs after block update/remove/duplicate; duplicated blocks set customizable: false; tests assert recalc calls.
JourneyCustomizationField Integration
apis/api-journeys/src/app/modules/journeyCustomizationField/journeyCustomizationField.module.ts, .../journeyCustomizationField.resolver.ts, .../journeyCustomizationField.resolver.spec.ts
Injects JourneyCustomizableService into customization-field resolver and calls recalculate(journeyId) after persistence; tests wired to mock the service and expect recalc.
Pothos / TS Schema Types
apis/api-journeys-modern/src/schema/journey/journey.ts, apis/api-journeys-modern/src/schema/journey/inputs/journeyUpdateInput.ts
Exposes customizable in Pothos/TypeScript GraphQL schema and adds the field to JourneyUpdateInput type.
Tests / Fixtures Updated
apis/api-journeys-modern/src/workers/emailEvents/service/...spec.ts, apis/api-journeys/src/app/modules/.../*.spec.ts, apis/api-journeys/src/app/modules/host/host.resolver.spec.ts, apis/api-journeys/src/app/modules/journeyTheme/journeyTheme.resolver.spec.ts
Adds customizable: null or relevant values to journey fixtures and updates test modules to provide/mocK JourneyCustomizableService where needed.
Module Providers / DI
apis/api-journeys/src/app/modules/event/event.module.ts, apis/api-journeys/src/app/modules/visitor/visitor.module.ts, apis/api-journeys/src/app/modules/block/block.module.ts, apis/api-journeys/src/app/modules/journeyCustomizationField/journeyCustomizationField.module.ts
Adds JourneyCustomizableService to providers arrays so modules can trigger recalculation.

Sequence Diagram

sequenceDiagram
    participant Client as Client
    participant Resolver as Resolver
    participant Service as DomainService
    participant JourneyCustomizable as JourneyCustomizableService
    participant Prisma as PrismaService
    participant DB as Database

    Client->>Resolver: mutate (updateBlock / updateJourney / duplicate / persistCustomizationField)
    Resolver->>Service: call domain method
    Service->>Prisma: perform DB transaction (create/update/delete)
    Prisma->>DB: persist changes
    DB-->>Prisma: ack
    Prisma-->>Service: transaction result
    Service->>JourneyCustomizable: recalculate(journeyId)
    JourneyCustomizable->>Prisma: fetch journey, blocks, actions, logo info
    Prisma->>DB: queries
    DB-->>Prisma: data
    JourneyCustomizable->>JourneyCustomizable: compute newCustomizable
    alt value differs
        JourneyCustomizable->>Prisma: update journey.customizable
        Prisma->>DB: update
        DB-->>Prisma: ack
    end
    JourneyCustomizable-->>Service: done
    Service-->>Resolver: return original result
    Resolver-->>Client: mutation response
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat: add customizable field to journey, and journey customizable service' accurately describes the main changes: adding a customizable boolean field to the Journey entity and introducing a new JourneyCustomizableService. It is clear, specific, and directly related to the core features being implemented.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch jianweichong/nes-1400-backend-auto-detect-journeycustomizable-via-recalculation

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

…-backend-auto-detect-journeycustomizable-via-recalculation
@nx-cloud
Copy link

nx-cloud bot commented Mar 5, 2026

View your CI Pipeline Execution ↗ for commit 3eef1f6

Command Status Duration Result
nx run journeys-admin-e2e:e2e ✅ Succeeded 31s View ↗
nx run journeys-e2e:e2e ✅ Succeeded 27s View ↗
nx run watch-e2e:e2e ✅ Succeeded 28s View ↗
nx run resources-e2e:e2e ✅ Succeeded 22s View ↗
nx run videos-admin-e2e:e2e ✅ Succeeded 4s View ↗
nx run player-e2e:e2e ✅ Succeeded 3s View ↗
nx run short-links-e2e:e2e ✅ Succeeded 3s View ↗
nx run-many --target=vercel-alias --projects=jo... ✅ Succeeded 2s View ↗
Additional runs (20) ✅ Succeeded ... View ↗

☁️ Nx Cloud last updated this comment at 2026-03-09 03:42:36 UTC

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
apis/api-gateway/schema.graphql (1)

4518-4550: ⚠️ Potential issue | 🟠 Major

Keep customizable out of JourneyUpdateInput.

This flag is described by the PR as derived from journey content via recalculation. Making it client-writable allows callers to persist a value that no longer matches the actual blocks/actions/media until some later recalculation happens. Keep it queryable on Journey, but remove it from the public update input.

Suggested change
 input JourneyUpdateInput `@join__type`(graph: API_JOURNEYS)  `@join__type`(graph: API_JOURNEYS_MODERN)  {
   title: String
   languageId: String
   themeMode: ThemeMode
   themeName: ThemeName
   description: String
   creatorDescription: String
   creatorImageBlockId: ID
   primaryImageBlockId: ID
   slug: String
   seoTitle: String
   seoDescription: String
   hostId: String
   strategySlug: String
   tagIds: [ID!]
   website: Boolean
   showShareButton: Boolean
   showLikeButton: Boolean
   showDislikeButton: Boolean
   displayTitle: String
   showHosts: Boolean
   showChatButtons: Boolean
   showReactionButtons: Boolean
   showLogo: Boolean
   showMenu: Boolean
   showDisplayTitle: Boolean
   menuButtonIcon: JourneyMenuButtonIcon
   menuStepBlockId: ID
   logoImageBlockId: ID
   socialNodeX: Int
   socialNodeY: Int
-  customizable: Boolean
 }

Based on learnings: the showAssistant field was intentionally excluded from JourneyUpdateInput because it is controlled through direct database operations rather than GraphQL mutations, while remaining queryable.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apis/api-gateway/schema.graphql` around lines 4518 - 4550, Remove the
client-writable customizable field from the JourneyUpdateInput input type so
clients cannot set it; edit the JourneyUpdateInput definition (remove the
customizable: Boolean line), keep customizable as a read-only field on the
Journey type for queries, and regenerate any GraphQL/typegen artifacts and
update any input validators or resolver tests that assumed the field existed to
ensure clients cannot persist derived values via update mutations.
🧹 Nitpick comments (2)
apis/api-journeys/src/app/modules/journey/journey.resolver.spec.ts (1)

2475-2499: Add coverage for the other derived-field transitions.

These cases only guard the website and template=true paths. A couple of assertions for journeyCustomizationDescription / logoImageBlockId updates and template=false clearing customizable would catch the stale-state paths in journeyUpdate() and journeyTemplate().

Also applies to: 2841-2849

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apis/api-journeys/src/app/modules/journey/journey.resolver.spec.ts` around
lines 2475 - 2499, Add tests to cover other derived-field transitions by
asserting recalculate is called or not for updates to
journeyCustomizationDescription and logoImageBlockId and for template toggles:
extend tests around resolver.journeyUpdate to include cases where input contains
journeyCustomizationDescription or logoImageBlockId (mock
prismaService.journey.findUnique and update as in existing tests) and expect
journeyCustomizableService.recalculate('journeyId') to be called; also add tests
for resolver.journeyTemplate where template=true should set customizable and
trigger recalculate and template=false should clear customizable and ensure
journeyCustomizableService.recalculate is not called (or is called as
appropriate), using the same mocked journey fixtures and prismaService methods
as in current tests.
apis/api-journeys/src/app/modules/journey/journeyCustomizable.service.ts (1)

39-42: Select only the columns used by the recalculation.

This runs after block update/remove/restore flows, so include: { action: true } pulls every block and action column on a hot path. The checks below only read id, typename, customizable, action.customizable, and action.blockId.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apis/api-journeys/src/app/modules/journey/journeyCustomizable.service.ts`
around lines 39 - 42, The query in this.prismaService.block.findMany pulls
entire block and action records; limit the selected columns to only those used
by the recalculation: select block.id, block.typename, block.customizable and
for the relation use action: select { customizable, blockId } (keep the same
where filter { journeyId, deletedAt: null }). Update the findMany call to use
select instead of include so only these fields are fetched.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apis/api-journeys/src/app/modules/journey/journey.resolver.ts`:
- Around line 1114-1119: When updating a journey, turning input.template to
false can leave customizable true and the resolver currently returns the
pre-recalc row; fix by ensuring customizable is cleared and the returned row is
the final persisted state: if input.template === false, set input.customizable =
false (so prismaService.journey.update(...) persists customizable:false), still
call this.journeyCustomizableService.recalculate(id) as before, then reload the
journey (e.g. await this.prismaService.journey.findUnique({ where: { id } }))
and return that fresh record instead of the original updatedJourney; reference
prismaService.journey.update, this.journeyCustomizableService.recalculate,
updatedJourney, input.template and id to locate changes.
- Around line 891-894: The returned journey can be stale because recalculate()
is only called when input.website changes and the function returns result before
the recalculation is persisted; update the logic in journey.resolver.ts to call
this.journeyCustomizableService.recalculate(id) whenever any of the fields that
affect customizable state change (website, journeyCustomizationDescription,
logoImageBlockId), await the recalculate() call before returning, and ensure you
return the post-recalculation journey (either by applying the recalculated
values to result or reloading the journey after recalculate) so
journey.customizable is accurate.

In
`@libs/prisma/journeys/db/migrations/20260302193727_20260302193725/migration.sql`:
- Around line 1-2: The migration adds Journey.customizable with DEFAULT false
but leaves historical rows incorrect; add a companion backfill that recomputes
and sets Journey.customizable for all existing journeys (either as an immediate
SQL update in the same migration or as a guaranteed post-deploy job) by scanning
the related entities that determine customizability (blocks, actions, media, or
whatever domain tables/functions your app uses) and setting Journey.customizable
= true where those checks indicate customization; ensure the backfill targets
every Journey row and is idempotent and logged so the derived column reflects
historical state before relying on it.

---

Outside diff comments:
In `@apis/api-gateway/schema.graphql`:
- Around line 4518-4550: Remove the client-writable customizable field from the
JourneyUpdateInput input type so clients cannot set it; edit the
JourneyUpdateInput definition (remove the customizable: Boolean line), keep
customizable as a read-only field on the Journey type for queries, and
regenerate any GraphQL/typegen artifacts and update any input validators or
resolver tests that assumed the field existed to ensure clients cannot persist
derived values via update mutations.

---

Nitpick comments:
In `@apis/api-journeys/src/app/modules/journey/journey.resolver.spec.ts`:
- Around line 2475-2499: Add tests to cover other derived-field transitions by
asserting recalculate is called or not for updates to
journeyCustomizationDescription and logoImageBlockId and for template toggles:
extend tests around resolver.journeyUpdate to include cases where input contains
journeyCustomizationDescription or logoImageBlockId (mock
prismaService.journey.findUnique and update as in existing tests) and expect
journeyCustomizableService.recalculate('journeyId') to be called; also add tests
for resolver.journeyTemplate where template=true should set customizable and
trigger recalculate and template=false should clear customizable and ensure
journeyCustomizableService.recalculate is not called (or is called as
appropriate), using the same mocked journey fixtures and prismaService methods
as in current tests.

In `@apis/api-journeys/src/app/modules/journey/journeyCustomizable.service.ts`:
- Around line 39-42: The query in this.prismaService.block.findMany pulls entire
block and action records; limit the selected columns to only those used by the
recalculation: select block.id, block.typename, block.customizable and for the
relation use action: select { customizable, blockId } (keep the same where
filter { journeyId, deletedAt: null }). Update the findMany call to use select
instead of include so only these fields are fetched.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: fa707768-01dd-427d-ac4d-1d1ab49c527b

📥 Commits

Reviewing files that changed from the base of the PR and between e1b8086 and 8d65512.

⛔ Files ignored due to path filters (4)
  • apis/api-journeys/src/__generated__/graphql.ts is excluded by !**/__generated__/**
  • apis/api-journeys/src/app/__generated__/graphql.ts is excluded by !**/__generated__/**
  • apps/journeys-admin/__generated__/globalTypes.ts is excluded by !**/__generated__/**
  • libs/shared/gql/src/__generated__/graphql-env.d.ts is excluded by !**/__generated__/**
📒 Files selected for processing (29)
  • .claude/rules/backend/customizable-blocks.md
  • .cursor/rules/customizable-blocks.mdc
  • apis/api-gateway/schema.graphql
  • apis/api-journeys-modern/schema.graphql
  • apis/api-journeys-modern/src/schema/journey/inputs/journeyUpdateInput.ts
  • apis/api-journeys-modern/src/schema/journey/journey.ts
  • apis/api-journeys-modern/src/workers/emailEvents/service/fetchEmailDetails.spec.ts
  • apis/api-journeys-modern/src/workers/emailEvents/service/processUserIds.spec.ts
  • apis/api-journeys-modern/src/workers/emailEvents/service/service.spec.ts
  • apis/api-journeys/schema.graphql
  • apis/api-journeys/src/app/modules/block/block.module.ts
  • apis/api-journeys/src/app/modules/block/block.resolver.spec.ts
  • apis/api-journeys/src/app/modules/block/block.resolver.ts
  • apis/api-journeys/src/app/modules/block/block.service.spec.ts
  • apis/api-journeys/src/app/modules/block/block.service.ts
  • apis/api-journeys/src/app/modules/block/videoTrigger/videoTrigger.resolver.spec.ts
  • apis/api-journeys/src/app/modules/host/host.resolver.spec.ts
  • apis/api-journeys/src/app/modules/journey/journey.graphql
  • apis/api-journeys/src/app/modules/journey/journey.module.ts
  • apis/api-journeys/src/app/modules/journey/journey.resolver.spec.ts
  • apis/api-journeys/src/app/modules/journey/journey.resolver.ts
  • apis/api-journeys/src/app/modules/journey/journeyCustomizable.service.spec.ts
  • apis/api-journeys/src/app/modules/journey/journeyCustomizable.service.ts
  • apis/api-journeys/src/app/modules/journeyCustomizationField/journeyCustomizationField.module.ts
  • apis/api-journeys/src/app/modules/journeyCustomizationField/journeyCustomizationField.resolver.spec.ts
  • apis/api-journeys/src/app/modules/journeyCustomizationField/journeyCustomizationField.resolver.ts
  • apis/api-journeys/src/app/modules/journeyTheme/journeyTheme.resolver.spec.ts
  • libs/prisma/journeys/db/migrations/20260302193727_20260302193725/migration.sql
  • libs/prisma/journeys/db/schema.prisma

@github-actions github-actions bot temporarily deployed to Preview - player March 6, 2026 00:02 Inactive
@github-actions github-actions bot temporarily deployed to Preview - short-links March 6, 2026 00:02 Inactive
@github-actions
Copy link
Contributor

github-actions bot commented Mar 6, 2026

The latest updates on your projects.

Name Status Preview Updated (UTC)
player ✅ Ready player preview Mon Mar 9 16:37:30 NZDT 2026

@github-actions github-actions bot requested a deployment to Preview - resources March 6, 2026 00:04 Pending
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

♻️ Duplicate comments (2)
apis/api-journeys/src/app/modules/journey/journey.resolver.ts (2)

1120-1125: ⚠️ Potential issue | 🟠 Major

Turning a template off can leave customizable stuck on.

When input.template is false, recalculate() exits immediately for non-templates, so an existing customizable: true value is never cleared. This path also returns the pre-recalculation row. Clear customizable during the update when de-templating, then reload the final journey before returning it.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apis/api-journeys/src/app/modules/journey/journey.resolver.ts` around lines
1120 - 1125, When de-templating (input.template === false) ensure customizable
is cleared during the update and return the final DB row after recalculation: in
the block that calls prismaService.journey.update(...) and
journeyCustomizableService.recalculate(id), include customizable: false in the
update data when input.template is explicitly false (to avoid leaving
customizable stuck on), call recalculate(id) afterward, then reload the journey
via prismaService.journey.findUnique({ where: { id } }) (or equivalent) and
return that reloaded row instead of the pre-recalculation updatedJourney.

897-900: ⚠️ Potential issue | 🟠 Major

The recalculation trigger is still too narrow, and the returned journey can be stale.

recalculate() only runs when input.website is present, even though the derived flag also depends on other persisted fields such as logoImageBlockId. And because result is returned without a reload, journeyUpdate() can respond with the old customizable value even when recalculation does run.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apis/api-journeys/src/app/modules/journey/journey.resolver.ts` around lines
897 - 900, The update only calls journeyCustomizableService.recalculate(id) when
input.website is set and returns the pre-recalc result, causing stale
customizable flags; modify the logic in the journeyUpdate resolver so you
trigger recalculate whenever any customizable-dependent fields change (e.g.,
website, logoImageBlockId, and other persisted customizable fields) or simply
always call journeyCustomizableService.recalculate(id) after successful update,
and then reload the journey (refetch the updated record) before returning so the
response reflects the recalculated customizable values.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apis/api-journeys/schema.graphql`:
- Line 2297: The field "customizable" is read-only and must not be writable via
the public API: remove "customizable" from the JourneyUpdateInput type while
keeping it on the Journey type so queries can still read it; locate the GraphQL
schema definitions for Journey and JourneyUpdateInput and delete the
"customizable: Boolean" entry from JourneyUpdateInput (leave the
Journey.customizable field unchanged) so the server continues to compute it but
clients cannot submit it in updates.

In `@apis/api-journeys/src/app/modules/journey/journey.resolver.ts`:
- Around line 631-634: The duplicate seeds customizable from
journey.customizable too early (using template: duplicateAsTemplate and
customizable: duplicateAsTemplate ? (journey.customizable ?? false) : false);
instead, after the clone's blocks/actions/media/fields are copied and the cloned
journey is fully saved, reload the cloned journey from the DB and
recalculate/set its customizable based on the actual copied content, then return
that freshly loaded journey; update the code paths that create the duplicate
(look for duplicateAsTemplate, the customizable assignment, and the post-clone
save/return logic) so the final returned object reflects the recomputed
customizable value rather than the original source flag.

---

Duplicate comments:
In `@apis/api-journeys/src/app/modules/journey/journey.resolver.ts`:
- Around line 1120-1125: When de-templating (input.template === false) ensure
customizable is cleared during the update and return the final DB row after
recalculation: in the block that calls prismaService.journey.update(...) and
journeyCustomizableService.recalculate(id), include customizable: false in the
update data when input.template is explicitly false (to avoid leaving
customizable stuck on), call recalculate(id) afterward, then reload the journey
via prismaService.journey.findUnique({ where: { id } }) (or equivalent) and
return that reloaded row instead of the pre-recalculation updatedJourney.
- Around line 897-900: The update only calls
journeyCustomizableService.recalculate(id) when input.website is set and returns
the pre-recalc result, causing stale customizable flags; modify the logic in the
journeyUpdate resolver so you trigger recalculate whenever any
customizable-dependent fields change (e.g., website, logoImageBlockId, and other
persisted customizable fields) or simply always call
journeyCustomizableService.recalculate(id) after successful update, and then
reload the journey (refetch the updated record) before returning so the response
reflects the recalculated customizable values.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: c6734871-a554-43b1-b508-561dd6a5ef5a

📥 Commits

Reviewing files that changed from the base of the PR and between 8d65512 and 611fac3.

⛔ Files ignored due to path filters (2)
  • apis/api-journeys/src/__generated__/graphql.ts is excluded by !**/__generated__/**
  • apis/api-journeys/src/app/__generated__/graphql.ts is excluded by !**/__generated__/**
📒 Files selected for processing (6)
  • apis/api-gateway/schema.graphql
  • apis/api-journeys/schema.graphql
  • apis/api-journeys/src/app/modules/block/videoTrigger/videoTrigger.resolver.spec.ts
  • apis/api-journeys/src/app/modules/journey/journey.graphql
  • apis/api-journeys/src/app/modules/journey/journey.resolver.spec.ts
  • apis/api-journeys/src/app/modules/journey/journey.resolver.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • apis/api-journeys/src/app/modules/block/videoTrigger/videoTrigger.resolver.spec.ts
  • apis/api-journeys/src/app/modules/journey/journey.graphql

@github-actions
Copy link
Contributor

github-actions bot commented Mar 6, 2026

The latest updates on your projects.

Name Status Preview Updated (UTC)
short-links ✅ Ready short-links preview Mon Mar 9 16:37:17 NZDT 2026

@github-actions
Copy link
Contributor

github-actions bot commented Mar 6, 2026

Warnings
⚠️ ❗ Big PR (842 changes)

(change count - 842): Pull Request size seems relatively large. If Pull Request contains multiple changes, split each into separate PR will helps faster, easier review.

Generated by 🚫 dangerJS against 3eef1f6

@github-actions github-actions bot temporarily deployed to Preview - videos-admin March 6, 2026 00:12 Inactive
@github-actions github-actions bot temporarily deployed to Preview - journeys March 6, 2026 00:12 Inactive
@github-actions github-actions bot temporarily deployed to Preview - resources March 6, 2026 00:12 Inactive
@github-actions github-actions bot temporarily deployed to Preview - videos-admin March 8, 2026 21:19 Inactive
@github-actions github-actions bot temporarily deployed to Preview - journeys-admin March 8, 2026 21:19 Inactive
@github-actions github-actions bot temporarily deployed to Preview - short-links March 8, 2026 21:19 Inactive
@github-actions github-actions bot temporarily deployed to Preview - player March 8, 2026 21:19 Inactive
@github-actions github-actions bot temporarily deployed to Preview - journeys March 8, 2026 21:41 Inactive
@github-actions github-actions bot temporarily deployed to Preview - journeys-admin March 8, 2026 21:41 Inactive
@github-actions github-actions bot temporarily deployed to Preview - videos-admin March 8, 2026 21:41 Inactive
@github-actions github-actions bot temporarily deployed to Preview - player March 8, 2026 21:41 Inactive
@github-actions github-actions bot temporarily deployed to Preview - resources March 8, 2026 21:41 Inactive
@github-actions github-actions bot temporarily deployed to Preview - short-links March 8, 2026 21:41 Inactive
@github-actions github-actions bot temporarily deployed to Preview - watch March 8, 2026 21:41 Inactive
…ions

- Consolidated instructions for adding a `customizable` field to new block and action types by removing redundant steps and clarifying the update logic in `JourneyCustomizableService.recalculate()`. This enhances clarity and ensures developers understand the necessary adjustments for the new field.
@github-actions github-actions bot temporarily deployed to Preview - player March 8, 2026 21:50 Inactive
@github-actions github-actions bot temporarily deployed to Preview - resources March 8, 2026 21:50 Inactive
@github-actions github-actions bot temporarily deployed to Preview - watch March 8, 2026 21:50 Inactive
@github-actions github-actions bot temporarily deployed to Preview - journeys-admin March 8, 2026 21:50 Inactive
@github-actions github-actions bot temporarily deployed to Preview - videos-admin March 8, 2026 21:50 Inactive
@github-actions github-actions bot temporarily deployed to Preview - journeys March 8, 2026 21:50 Inactive
@github-actions github-actions bot temporarily deployed to Preview - short-links March 8, 2026 21:50 Inactive
customizable: true,
journeyCustomizationDescription: true,
logoImageBlockId: true,
website: true
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NIT: We can add the count for number of customizable fields by doing this. It can save not having to call a second query.

Suggested change
website: true
website: true,
_count: { select: { journeyCustomizationField: true } }

await this.prismaService.journeyCustomizationField.count({
where: { journeyId }
})

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you do the above you can do this instead:

Suggested change
const fieldsCount = journey._count.journeyCustomizationField

…ustomizationFields

- Modified the service to include _count in the journey query, allowing for more efficient counting of journeyCustomizationFields.
- Adjusted tests to reflect the new structure, ensuring accurate validation of customizable logic based on the presence of editable text fields.
@github-actions github-actions bot temporarily deployed to Preview - player March 9, 2026 00:42 Inactive
@github-actions github-actions bot temporarily deployed to Preview - short-links March 9, 2026 00:42 Inactive
@stage-branch-merger
Copy link

I see you added the "on stage" label, I'll get this merged to the stage branch!

@stage-branch-merger
Copy link

Merge conflict attempting to merge this into stage. Please fix manually.

@jianwei1
Copy link
Contributor Author

jianwei1 commented Mar 9, 2026

Merge conflict attempting to merge this into stage. Please fix manually.

Have merged onto stage. No merge conflicts when I did it

@stage-branch-merger
Copy link

Merge conflict attempting to merge this into stage. Please fix manually.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants