Skip to content

Conversation

@mikeallisonJS
Copy link
Collaborator

@mikeallisonJS mikeallisonJS commented Jan 27, 2026

Summary by CodeRabbit

  • New Features

    • Added a backfill action/mutation to clear and re-export Google Sheets sync data.
    • Exports and syncs now enqueue asynchronous worker jobs (create, append, backfill) instead of performing large writes inline.
  • Changes

    • Live sync appends values with normalization and deduplication to avoid duplicate entries.
    • Export flows use timezone-aware formatting.
    • Visitor export mutation simplified — removed filter/select parameters; destination and timezone remain.

✏️ Tip: You can customize this high-level summary in your review settings.

mikeallisonJS and others added 20 commits January 23, 2026 01:28
…Spaces types

This update introduces the oauthStale field to the IntegrationGoogle and IntegrationGrowthSpaces types in the GraphQL schema, indicating whether OAuth credentials are stale. Additionally, the field is integrated into the relevant resolvers and service logic to manage OAuth token refresh states effectively.
This update introduces the StaleOAuthError class to manage scenarios where Google integration OAuth credentials are stale, requiring re-authorization. The error is integrated into the getTeamGoogleAccessToken and getIntegrationGoogleAccessToken functions, preventing token refresh attempts when the integration is marked as stale. Additionally, the appendEventToGoogleSheets function is updated to skip syncing silently when a StaleOAuthError is encountered.
…logic

This update removes the StaleOAuthError class and its associated handling from the Google authentication functions. The logic for marking integrations as stale and throwing errors has been eliminated, simplifying the getTeamGoogleAccessToken and getIntegrationGoogleAccessToken functions. The appendEventToGoogleSheets function has also been adjusted to directly retrieve the access token without handling stale integration scenarios.
…upport

This update introduces the exportOrder property to journey blocks and modifies the export logic to utilize blockId for data mapping. The changes ensure that data is aligned correctly in exports, preserving the order of columns based on exportOrder. Additionally, the implementation includes updates to the CSV stringifier to handle blockId-based column matching, improving the overall export process for Google Sheets and CSV files.
…multiple schemas

This commit removes the oauthStale field from the IntegrationGoogle type in various GraphQL schema files, including api-gateway, api-journeys, and api-journeys-modern. The change ensures consistency across the integration types and simplifies the integration model.
This commit enhances the journey visitor export functionality by building a lookup map from the row data, ensuring that values are aligned correctly with the final header order. This change simplifies the process of matching column values and improves the overall export process for Google Sheets.
This commit introduces error logging for the block export order updates in the journeyVisitorExportToGoogleSheet mutation. If an error occurs during the update process, it logs the error details without rethrowing, ensuring that the mutation can still return success after the sheet export. This enhances the robustness of the export functionality.
…tion

This update introduces a job queue for syncing events to Google Sheets, ensuring that events are processed sequentially to avoid race conditions. The appendEventToGoogleSheets function has been modified to fetch sync configurations upfront and add jobs to the queue with retry logic. Additionally, the server's run function now supports concurrency settings, specifically set to 1 for the Google Sheets sync worker to maintain data integrity during processing.
This commit refactors the event utility tests to incorporate a new Google Sheets sync queue. It replaces the previous email queue mock with a dedicated Google Sheets sync queue and updates the test cases to ensure proper setup and assertions for both email and Google Sheets sync functionalities. Additionally, it introduces checks for null queue scenarios to enhance robustness in the testing framework.
…leSheet mutation

This commit refactors the column mapping logic in the journeyVisitorExportToGoogleSheet mutation by removing the unnecessary index parameter from the map function. This change enhances code readability and maintains the functionality of identifying column positions for export.
This commit introduces a new clearSheet function that allows for clearing all data from a specified Google Sheets tab while preserving the sheet itself. This functionality is particularly useful for backfill operations that require replacing existing content. Additionally, the Google Sheets sync job types have been expanded to include backfill and create operations, enhancing the overall sync capabilities.
@mikeallisonJS mikeallisonJS requested a review from tanflem January 27, 2026 23:39
@mikeallisonJS mikeallisonJS self-assigned this Jan 27, 2026
@mikeallisonJS mikeallisonJS changed the title refactor: sheets bull queue refactor: sheets backfill Jan 27, 2026
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 27, 2026

Walkthrough

Moves Google Sheets syncing to a queue-driven system: adds BullMQ job types and queue, worker services (create/backfill/append), GraphQL mutation for backfill, resolver changes to enqueue jobs, a sheets.clearSheet helper, and test helpers to inject mock queues. Tests updated to expect queue interactions.

Changes

Cohort / File(s) Summary
Google Sheets API Library
apis/api-journeys-modern/src/lib/google/sheets.ts
Adds exported clearSheet(accessToken: string, spreadsheetId: string, sheetTitle: string): Promise<void> which calls Sheets API values:clear on range sheetTitle!A:ZZ and throws on non-ok responses.
Queue Types & Instance
apis/api-journeys-modern/src/workers/googleSheetsSync/queue.ts
Adds typed interfaces for GoogleSheetsSync records and job data (append/create/backfill), union type, type guards, and exports a BullMQ queue.
Worker Services
apis/api-journeys-modern/src/workers/googleSheetsSync/service/...
.../service/service.ts, .../service/create.ts, .../service/backfill.ts, .../service/index.ts
Adds dispatcher service routing jobs to create/backfill/append handlers; implements createService and backfillService that build headers, stream visitor rows, ensure/clear/write sheet data, and handle export lifecycle.
Append Flow & Live Merge
apis/api-journeys-modern/src/schema/journeyVisitor/export/googleSheetsLiveSync.ts
Changes cell-merge behavior to normalize and deduplicate semicolon-delimited tokens, appending non-duplicate new values instead of overwriting.
Event Sync Logic & Tests
apis/api-journeys-modern/src/schema/event/utils.ts, apis/api-journeys-modern/src/schema/event/utils.spec.ts
Replaces in-process Sheets operations with enqueueing append jobs to googleSheetsSync queue; adds __setGoogleSheetsSyncQueueForTests injector and ONE_HOUR constant; tests now mock/assert queue interactions.
Export Mutation & Tests
apis/api-journeys-modern/src/schema/journeyVisitor/journeyVisitorExportToGoogleSheet.mutation.ts, .../journeyVisitorExportToGoogleSheet.mutation.spec.ts
Resolver now creates/finds spreadsheet, creates GoogleSheetsSync record, and enqueues a create job; accepts timezone and exposes __setGoogleSheetsSyncQueueForExportTests test injector; tests updated to expect queued export jobs.
Backfill Mutation & Index
apis/api-journeys-modern/src/schema/googleSheetsSync/googleSheetsSyncBackfill.mutation.ts, apis/api-journeys-modern/src/schema/googleSheetsSync/index.ts
Adds googleSheetsSyncBackfill(id: ID!): GoogleSheetsSync! mutation with validation, permission checks, enqueues a backfill job, and exposes test injector __setGoogleSheetsSyncQueueForBackfillTests.
GraphQL Schema Changes
apis/api-gateway/schema.graphql, apis/api-journeys-modern/schema.graphql
Adds googleSheetsSyncBackfill mutation; removes filter and select args from journeyVisitorExportToGoogleSheet signature and requires timezone.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant Resolver as Export Mutation
    participant DB as Database
    participant Queue as GoogleSheets Sync Queue
    participant Worker as Create/Backfill Worker
    participant Sheets as Google Sheets API

    rect rgba(150, 200, 255, 0.5)
    Client->>Resolver: journeyVisitorExportToGoogleSheet(...)
    Resolver->>DB: validate integration & create/find spreadsheet
    Resolver->>DB: create GoogleSheetsSync record
    Resolver->>Queue: enqueue job (type: create/backfill)
    Resolver-->>Client: return
    end

    Queue->>Worker: deliver job
    Worker->>DB: load journey, visitors, headers
    Worker->>Sheets: ensure sheet exists
    Worker->>Sheets: clearSheet(...) (values:clear)
    Worker->>Sheets: write header + batched rows
    Worker->>DB: update block exportOrder (if needed)
    Worker-->>Queue: complete job
Loading
sequenceDiagram
    participant EventProducer as Event Mutation
    participant AppendFn as appendEventToGoogleSheets
    participant DB as Database
    participant Queue as GoogleSheets Sync Queue
    participant AppendWorker as Append Service
    participant Sheets as Google Sheets API

    EventProducer->>AppendFn: appendEventToGoogleSheets(row)
    AppendFn->>DB: fetch active syncs
    alt syncs exist
        AppendFn->>Queue: enqueue append job (row + syncs)
        AppendFn-->>EventProducer: return
        Queue->>AppendWorker: process append job
        AppendWorker->>Sheets: append row to sheet (merge/dedupe)
    else no syncs
        AppendFn-->>EventProducer: return (no-op)
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • tanflem
🚥 Pre-merge checks | ✅ 1 | ❌ 2
❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 58.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title 'refactor: sheets backfill' is vague and overly broad, using non-specific phrasing that doesn't convey the full scope of changes. While it mentions backfill, it obscures the substantial refactoring of Google Sheets synchronization from synchronous to asynchronous queue-driven processing. Consider using a more descriptive title that captures the primary architectural change, such as 'refactor: convert Google Sheets sync to queue-driven processing' or 'refactor: migrate sheets API calls to async job queue'
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

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

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch 00-00-MA-feat-sheets-backfill

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.

@github-actions
Copy link
Contributor

github-actions bot commented Jan 27, 2026

Warnings
⚠️ ❗ Big PR (1695 changes)

(change count - 1695): 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 fe51c56

@nx-cloud
Copy link

nx-cloud bot commented Jan 27, 2026

View your CI Pipeline Execution ↗ for commit fe51c56

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

☁️ Nx Cloud last updated this comment at 2026-01-29 01:53:41 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: 1

Caution

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

⚠️ Outside diff range comments (1)
apis/api-journeys-modern/src/schema/journeyVisitor/journeyVisitorExportToGoogleSheet.mutation.ts (1)

202-217: Consider checking deletedAt in existing sync query.

The query for existingSync doesn't filter by deletedAt: null. This means a soft-deleted sync could block creation of a new sync for the same journey/spreadsheet/sheet combination.

🐛 Suggested fix
 const existingSync = await prisma.googleSheetsSync.findFirst({
   where: {
     teamId: journey.teamId,
     journeyId,
     spreadsheetId,
-    sheetName
+    sheetName,
+    deletedAt: null
   }
 })
🤖 Fix all issues with AI agents
In `@apis/api-journeys-modern/src/workers/googleSheetsSync/queue.ts`:
- Around line 71-93: Change the three type-guard functions isAppendJob,
isBackfillJob, and isCreateJob to accept data: unknown and perform safe runtime
checks before using the 'in' operator or reading .type; specifically, first
ensure data is a non-null object (typeof data === 'object' && data !== null),
cast to a Record<string, unknown> (e.g., const obj = data as Record<string,
unknown>), then use 'type' in obj and check that obj.type is a string when
comparing to 'append'/'backfill'/'create'; for isAppendJob preserve legacy
behavior by returning true when obj lacks a 'type' property, otherwise compare
obj.type === 'append'.
🧹 Nitpick comments (9)
apis/api-journeys-modern/src/workers/server.ts (1)

28-38: Consider consolidating the concurrency validation logic.

The validation condition is duplicated: once for logging (lines 28) and again for constructing workerOptions (lines 36). Consider extracting to a validated variable to follow DRY:

♻️ Suggested refactor
-  if (concurrency != null && !(Number.isFinite(concurrency) && concurrency > 0)) {
+  const validConcurrency =
+    typeof concurrency === 'number' &&
+    Number.isFinite(concurrency) &&
+    concurrency > 0
+      ? concurrency
+      : undefined
+
+  if (concurrency != null && validConcurrency == null) {
     logger.warn(
       { queue: queueName, concurrency },
       'invalid concurrency; using default'
     )
   }

-  const workerOptions: ConstructorParameters<typeof Worker>[2] =
-    typeof concurrency === 'number' && Number.isFinite(concurrency) && concurrency > 0
-      ? { connection, concurrency }
-      : { connection }
+  const workerOptions: ConstructorParameters<typeof Worker>[2] =
+    validConcurrency != null
+      ? { connection, concurrency: validConcurrency }
+      : { connection }
apis/api-journeys-modern/src/schema/googleSheetsSync/googleSheetsSyncBackfill.mutation.ts (1)

97-121: Consider logging when the queue is unavailable.

When googleSheetsSyncQueue is null, the mutation succeeds silently without actually triggering a backfill. While this fail-safe pattern is consistent with other queue operations, users may be confused when nothing happens.

Consider adding a log or returning a different status when the queue is unavailable to aid debugging in production scenarios.

💡 Optional: Add logging for null queue
       // Enqueue the backfill job
       if (googleSheetsSyncQueue != null) {
         await googleSheetsSyncQueue.add(
           'google-sheets-sync-backfill',
           // ... job data
         )
+      } else {
+        console.warn('Google Sheets sync queue unavailable - backfill not enqueued')
       }
apis/api-journeys-modern/src/workers/googleSheetsSync/service/service.ts (3)

40-50: Consider extracting shared constant to reduce duplication.

The journeyBlockSelect constant is duplicated across service.ts, backfill.ts, and create.ts. Consider extracting it to a shared module to ensure consistency and reduce maintenance burden.


242-243: Unsafe type assertion with as any.

Casting idToBlock and journeyBlocks to any bypasses type safety. Consider defining proper types that match the expected interface of getCardHeading to maintain type safety.

♻️ Suggested approach

Define a type that satisfies the getCardHeading function signature instead of using as any:

// If getCardHeading expects BlockLike[], ensure journeyBlocks conform to that type
// or create a mapping function that transforms the data appropriately

298-312: Potential performance concern with large datasets.

Reading up to 1 million rows (A${firstDataRow}:A1000000) to find a visitor ID could be slow for sheets with many rows. Consider:

  1. Using a more bounded range based on expected data size
  2. Implementing binary search if data is sorted
  3. Caching visitor row indices
apis/api-journeys-modern/src/workers/googleSheetsSync/service/backfill.ts (1)

43-129: Significant code duplication with create.ts.

The getJourneyVisitors generator and the data row building logic (lines 284-304) are nearly identical to create.ts. Consider extracting these to a shared utility module to improve maintainability.

♻️ Suggested approach

Create a shared module like workers/googleSheetsSync/service/shared.ts:

// shared.ts
export interface JourneyVisitorExportRow {
  visitorId: string
  date: string
  [key: string]: string
}

export async function* getJourneyVisitors(
  journeyId: string,
  eventWhere: Prisma.EventWhereInput,
  timezone: string,
  batchSize: number = 1000
): AsyncGenerator<JourneyVisitorExportRow> {
  // ... shared implementation
}

Also applies to: 284-304

apis/api-journeys-modern/src/workers/googleSheetsSync/service/create.ts (1)

307-335: Potential issue with exportOrder calculation.

The exportOrder calculation subtracts baseColumns.length but uses findIndex which could return the same index for blocks with duplicate blockIds if deduplication wasn't perfect. Additionally, col.exportOrder == null check relies on the column having this field populated from the block, but new columns won't have it.

Also, Promise.all for individual block updates could be inefficient for many blocks. Consider using a transaction or batch update.

♻️ Suggested improvement
 if (blocksToUpdate.length > 0) {
   try {
-    await Promise.all(
-      blocksToUpdate.map(({ blockId, exportOrder }) =>
-        prisma.block.update({
-          where: { id: blockId },
-          data: { exportOrder }
-        })
-      )
-    )
+    await prisma.$transaction(
+      blocksToUpdate.map(({ blockId, exportOrder }) =>
+        prisma.block.update({
+          where: { id: blockId },
+          data: { exportOrder }
+        })
+      )
+    )
   } catch (error) {
apis/api-journeys-modern/src/schema/journeyVisitor/journeyVisitorExportToGoogleSheet.mutation.ts (2)

23-29: Inconsistent test helper naming.

This test helper is named __setGoogleSheetsSyncQueueForExportTests while utils.ts uses __setGoogleSheetsSyncQueueForTests. Consider using a consistent naming convention across the codebase.

♻️ Suggested fix
-export function __setGoogleSheetsSyncQueueForExportTests(
+export function __setGoogleSheetsSyncQueueForTests(
   mockQueue: any
 ): void {
   googleSheetsSyncQueue = mockQueue
 }

Alternatively, if both are intentionally separate (different module-level queue variables), ensure the distinction is documented.


31-31: Duplicate constant - consider centralizing.

ONE_HOUR is defined identically in utils.ts (line 49). Consider extracting to a shared constants module to avoid duplication.

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

🤖 Fix all issues with AI agents
In
`@apis/api-journeys-modern/src/schema/journeyVisitor/journeyVisitorExportToGoogleSheet.mutation.ts`:
- Around line 231-258: The created google-sheets sync record
(prisma.googleSheetsSync.create with syncData producing sync.id) can be left
orphaned if googleSheetsSyncQueue.add throws; change the flow to ensure
atomicity by either wrapping the record creation and queue.add in a single
transaction where possible, or by catching errors from googleSheetsSyncQueue.add
and deleting the newly created record (prisma.googleSheetsSync.delete({ where: {
id: sync.id } })) on failure; ensure you still surface the original error after
cleanup and preserve existing backoff/attempt/removeOnComplete options used when
calling googleSheetsSyncQueue.add.

In `@apis/api-journeys-modern/src/workers/googleSheetsSync/service/create.ts`:
- Around line 286-307: The code buffers all rows into the values array
(initialized with sanitizedHeaderRow) while iterating getJourneyVisitors, which
can OOM for large journeys; change create.ts to write the header once via
writeValues or writeValues({..., values: [sanitizedHeaderRow], append: false })
and then stream visitor rows in fixed-size batches: accumulate aligned rows
(using finalHeader and sanitizeGoogleSheetsCell) into a small batch array and
call writeValues with append: true for each batch, flushing the batch and
continuing until getJourneyVisitors completes; keep references to
getJourneyVisitors, sanitizedHeaderRow, finalHeader, values, and writeValues to
locate the changes.
- Around line 223-237: The current dedupe uses only blockId and drops additional
labels; update the Map keying logic in the header normalization block (where
headerMap and normalizedBlockHeaders are constructed from blockHeadersResult) to
use a composite key combining blockId and the normalizedLabel (e.g.,
`${blockId}-${normalizedLabel}`) so each distinct label per block becomes its
own entry; ensure you still normalize whitespace via the existing
normalizedLabel variable and keep the Map value shape { blockId, label } so
downstream row keys (which use blockId-label) align with these columns.
🧹 Nitpick comments (4)
apis/api-journeys-modern/src/schema/journeyVisitor/journeyVisitorExportToGoogleSheet.mutation.ts (2)

11-21: Silent catch block swallows import errors.

If the queue import fails for reasons other than being in test mode (e.g., misconfiguration, missing dependency), this will silently set the queue to null without any diagnostic output. Consider logging the error.

♻️ Suggested improvement
 } catch {
+  logger.warn('Failed to load googleSheetsSync queue, sync jobs will not be enqueued')
   googleSheetsSyncQueue = null
 }

23-27: Consider adding a type for the mock queue parameter.

Using any reduces type safety. A minimal interface would help catch test issues earlier.

♻️ Optional type improvement
+interface QueueLike {
+  add: (name: string, data: unknown, opts?: unknown) => Promise<unknown>
+}
+
 // Test helper to inject a mock queue
 // eslint-disable-next-line `@typescript-eslint/naming-convention`
-export function __setGoogleSheetsSyncQueueForExportTests(mockQueue: any): void {
+export function __setGoogleSheetsSyncQueueForExportTests(mockQueue: QueueLike | null): void {
   googleSheetsSyncQueue = mockQueue
 }
apis/api-journeys-modern/src/workers/server.ts (1)

28-43: Duplicate concurrency validation logic.

The concurrency value is validated twice: once for logging a warning (lines 28-36) and again when constructing workerOptions (lines 39-41). Consider consolidating to avoid redundancy.

♻️ Consolidated validation
+  const isValidConcurrency =
+    typeof concurrency === 'number' &&
+    Number.isFinite(concurrency) &&
+    concurrency > 0
+
   if (
-    concurrency != null &&
-    !(Number.isFinite(concurrency) && concurrency > 0)
+    concurrency != null && !isValidConcurrency
   ) {
     logger.warn(
       { queue: queueName, concurrency },
       'invalid concurrency; using default'
     )
   }

   const workerOptions: ConstructorParameters<typeof Worker>[2] =
-    typeof concurrency === 'number' &&
-    Number.isFinite(concurrency) &&
-    concurrency > 0
+    isValidConcurrency
       ? { connection, concurrency }
       : { connection }
apis/api-journeys-modern/src/workers/googleSheetsSync/service/create.ts (1)

43-124: Consider cursor-based pagination to avoid skip/offset drift and scale pain.

skip + orderBy can be slow on large tables and can miss/duplicate rows if new visitors/events arrive during the export. A cursor on (createdAt, id) keeps pagination stable and efficient.

…mezone and simplify event handling

This commit modifies the journeyVisitorExportToGoogleSheet mutation to accept a timezone parameter, allowing for better handling of date and time during exports. Additionally, it removes unused filter and select arguments, streamlining the mutation's functionality. The test cases have been updated accordingly to reflect these changes.
@github-actions github-actions bot temporarily deployed to Preview - short-links January 28, 2026 23:56 Inactive
@github-actions github-actions bot temporarily deployed to Preview - journeys-admin January 28, 2026 23:56 Inactive
@github-actions github-actions bot temporarily deployed to Preview - resources January 28, 2026 23:56 Inactive
@github-actions github-actions bot temporarily deployed to Preview - videos-admin January 28, 2026 23:56 Inactive
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: 1

Caution

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

⚠️ Outside diff range comments (1)
apis/api-journeys-modern/src/workers/googleSheetsSync/service/service.ts (1)

48-51: Guard against missing syncs for legacy jobs.

If a queued legacy job lacks syncs, syncs.length will throw and the job will fail. Add a safe check to tolerate undefined payloads.

Suggested fix
-  if (syncs.length === 0) return
+  if (!syncs?.length) return
🤖 Fix all issues with AI agents
In
`@apis/api-journeys-modern/src/schema/journeyVisitor/journeyVisitorExportToGoogleSheet.mutation.ts`:
- Around line 14-33: Change the untyped any usage to a type-only import for the
queue: define a type alias GoogleSheetsSyncQueue = typeof
import('../../workers/googleSheetsSync/queue').queue and declare
googleSheetsSyncQueue as GoogleSheetsSyncQueue | null (initialize to null)
instead of any; update the test helper __setGoogleSheetsSyncQueueForExportTests
to accept mockQueue: GoogleSheetsSyncQueue | null so callers and usages of
googleSheetsSyncQueue.add() get proper compile-time payload/type safety while
preserving the lazy runtime require behavior.

@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.

This update enhances the logic for appending values to Google Sheets by ensuring non-unique values are not duplicated. If the existing value is empty, the new value is added; otherwise, values are joined with a semicolon, preventing duplicates from being appended.
@stage-branch-merger
Copy link

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

@github-actions github-actions bot temporarily deployed to Preview - videos-admin January 29, 2026 01:01 Inactive
@github-actions github-actions bot temporarily deployed to Preview - short-links January 29, 2026 01:01 Inactive
@github-actions github-actions bot temporarily deployed to Preview - journeys-admin January 29, 2026 01:01 Inactive
@github-actions github-actions bot temporarily deployed to Preview - resources January 29, 2026 01:02 Inactive
@github-actions github-actions bot temporarily deployed to Preview - journeys January 29, 2026 01:02 Inactive
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: 1

🤖 Fix all issues with AI agents
In
`@apis/api-journeys-modern/src/schema/journeyVisitor/export/googleSheetsLiveSync.ts`:
- Around line 342-353: Normalize tokens before deduplication in the append
logic: treat newValue and existing tokens by trimming and removing any leading
sheet-escaping apostrophe before comparing, and short-circuit when newValue is
empty or whitespace-only; in the block that builds existingTokens and checks
includes (references: existingValue, newValue, existingTokens), map tokens
through a normalizer (trim + strip leading "'"), normalize newValue the same
way, skip appending if normalized newValue is empty or already present,
otherwise append the original newValue to preserve display formatting.

This update introduces a normalization function to trim and strip leading apostrophes from values before appending them to Google Sheets. It ensures that empty or whitespace-only values are not appended, improving data integrity and consistency.
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