Skip to content

Conversation

@waltergalvao
Copy link
Contributor

@waltergalvao waltergalvao commented Dec 24, 2025

Summary by CodeRabbit

  • New Features

    • Workspace Data Ingestion settings and a modal to schedule historical resyncs (1–365 days)
    • GraphQL-backed scheduling and a "last sync" lookup with client hooks for query & mutation
  • Improvements

    • Resync UI: live progress, last-triggered timestamp, refined settings navigation, icon and label updates, and a new reusable settings card component
    • Configurable resync window and improved progress reporting
  • Bug Fixes

    • Sync batches now reliably mark completion when no pull requests are returned

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

@coderabbitai
Copy link

coderabbitai bot commented Dec 24, 2025

Walkthrough

Adds a sync-batch feature (schema, services, validation, resolvers, hooks, UI) and integrates batch lifecycle into GitHub sync flows/workers; replaces CardOpenableSettings with CardSetting and updates related UI, icons, and routing.

Changes

Cohort / File(s) Summary
Sync Batch Core
apps/api/src/app/sync-batch/services/sync-batch.service.ts, apps/api/src/app/sync-batch/services/sync-batch.types.ts, apps/api/src/app/sync-batch/services/sync-batch.validation.ts
Add DEFAULT_SYNC_BATCH_SINCE_DAYS_AGO (365); require sinceDaysAgo in CreateSyncBatchArgs; add findSyncableRepositories() and findLastSyncBatch(); add Zod validation schema and input type.
GraphQL: schema & generated types
apps/api/src/app/sync-batch/sync-batch.schema.ts, packages/graphql-types/api.ts, packages/graphql-types/frontend/graphql.ts, packages/graphql-types/frontend/gql.ts
Add SyncBatch type, ScheduleSyncBatchInput, scheduleSyncBatch mutation, lastSyncBatch on Workspace, and update generated frontend documents/types and graphql overloads.
Resolvers & Transformer
apps/api/src/app/sync-batch/resolvers/mutations/schedule-sync-batch.mutation.ts, apps/api/src/app/sync-batch/resolvers/queries/last-sync-batch.query.ts, apps/api/src/app/sync-batch/resolvers/queries/sync-batch-progress.query.ts, apps/api/src/app/sync-batch/resolvers/transformers/sync-batch.transformer.ts
New mutation resolver (validation, paywall, 24h throttle, scheduling), field resolvers for workspace.lastSyncBatch and SyncBatch.progress, and transformer to shape SyncBatch payloads.
GitHub sync integration
apps/api/src/app/github/services/github-repository-pull-requests.service.ts, apps/api/src/app/github/services/github-repository.service.ts, apps/api/src/app/github/workers/github-sync-pull-request.worker.ts
Trigger maybeFinishSyncBatch(syncBatchId) when a repo sync yields no PRs; use DEFAULT_SYNC_BATCH_SINCE_DAYS_AGO for scheduling; move worker batch-completion call into first-attempt conditional.
Frontend hooks & API
apps/web/src/api/sync-batch.api.ts
Add useWorkspaceLastSyncBatchQuery() and useScheduleSyncBatchMutation() React Query hooks; mutation invalidates last-sync-batch query on settle.
Settings UI & routing
apps/web/src/app/settings/data-ingestion/page.tsx, apps/web/src/app/settings/workspace/page.tsx, apps/web/src/app/settings/workspace/resync/page.tsx, apps/web/src/routes.tsx
Add Data Ingestion page, workspace resync modal/page, wire lastSyncBatch hook for UI state, and add /settings/workspace/resync route.
Component refactor: card
apps/web/src/components/card-openable-settings/* (removed), apps/web/src/components/card-setting/* (added)
Remove CardOpenableSettings; add CardSetting with isLoading/skeleton support and barrel export; update consumers to new component.
UI/icon/UX tweaks
apps/web/src/app/humans/teams/.../alerts/page.tsx, apps/web/src/app/humans/teams/.../health-and-performance/page.tsx, apps/web/src/app/humans/teams/.../pull-requests/page.tsx, apps/web/src/app/settings/pull-request-settings/page.tsx, apps/web/src/app/settings/components/subnav-settings/subnav-settings.tsx
Replace IconAspectRatio with IconRuler in multiple places; change Members→Users label and icon; switch NavLink active detection to prefix-based.
Misc frontend component changes
apps/web/src/components/icon-info/icon-info.tsx
Widen IconInfoProps.tooltip type from string to `string
Workspace schema & deployments
apps/api/src/app/workspaces/resolvers/workspaces.schema.ts, apps/api/src/app/deployment/services/deployment.service.ts
Add gitUninstallUrl and initialSyncProgress fields to Workspace schema; change deployment pagination ordering to deployedAt desc.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • feat: sync batch #55 — Overlaps sync-batch feature additions and integration points (scheduleSyncBatch / maybeFinishSyncBatch).
  • feat: customize PR sizing #33 — Modifies github-sync-pull-request.worker.ts and PR processing logic; related at worker/control-flow level.
  • feat: alerts #45 — Also touches the GitHub PR sync worker and related sync-batch behaviors.

Suggested labels

enhancement

Suggested reviewers

  • sweetrdev

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title 'feat: allow users to trigger a full data re-sync' accurately captures the main objective of the changeset, which adds comprehensive UI and backend infrastructure for users to manually initiate full workspace data resynchronization with configurable historical lookback periods.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ 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 feat/manual-full-sync

📜 Recent review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between dfd4c0c and 3979d5b.

📒 Files selected for processing (1)
  • apps/api/src/app/sync-batch/resolvers/mutations/schedule-sync-batch.mutation.ts
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-01-30T06:09:36.043Z
Learnt from: waltergalvao
Repo: sweetr-dev/sweetr.dev PR: 44
File: apps/api/src/app/integrations/resolvers/mutations/send-test-message.mutation.ts:30-30
Timestamp: 2025-01-30T06:09:36.043Z
Learning: GraphQL mutations in this codebase already handle errors and show user-facing error messages. Additional try-catch blocks in mutation resolvers are not needed as errors are properly propagated and handled at the GraphQL layer.

Applied to files:

  • apps/api/src/app/sync-batch/resolvers/mutations/schedule-sync-batch.mutation.ts
🧬 Code graph analysis (1)
apps/api/src/app/sync-batch/resolvers/mutations/schedule-sync-batch.mutation.ts (7)
apps/api/src/lib/logger.ts (1)
  • logger (21-76)
apps/api/src/app/validator.service.ts (1)
  • validateInputOrThrow (12-34)
apps/api/src/app/sync-batch/services/sync-batch.validation.ts (1)
  • scheduleSyncBatchValidationSchema (4-7)
apps/api/src/app/billing/services/billing.service.ts (1)
  • protectWithPaywall (142-156)
apps/api/src/app/sync-batch/services/sync-batch.service.ts (3)
  • findLastSyncBatch (264-273)
  • findSyncableRepositories (253-262)
  • scheduleSyncBatch (20-42)
apps/api/src/app/errors/exceptions/input-validation.exception.ts (1)
  • InputValidationException (11-26)
apps/api/src/app/sync-batch/resolvers/transformers/sync-batch.transformer.ts (1)
  • transformSyncBatch (4-13)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: integration-test
🔇 Additional comments (1)
apps/api/src/app/sync-batch/resolvers/mutations/schedule-sync-batch.mutation.ts (1)

15-64: Well-structured mutation following established patterns.

The implementation correctly:

  • Validates input and enforces paywall protection
  • Implements 24-hour cooldown with accurate date-fns calculations
  • Provides clear user-facing error messages with proper singular/plural handling
  • Handles the edge case of no syncable repositories

One minor consideration: there's a potential race condition between findLastSyncBatch (line 26) and scheduleSyncBatch (line 53). Concurrent requests could both pass the 24-hour check and schedule multiple batches. Given this is rate-limiting rather than a critical business constraint, the risk is low, but you may want to consider a database-level unique constraint or lock if stricter enforcement is needed in the future.

Based on learnings, no additional try-catch is needed as the GraphQL layer handles errors.


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.

Copy link

@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

🧹 Nitpick comments (9)
apps/api/src/app/sync-batch/resolvers/transformers/sync-batch.transformer.ts (1)

4-13: Remove redundant sinceDaysAgo assignment.

Line 11 explicitly assigns sinceDaysAgo: syncBatch.sinceDaysAgo, but this is redundant since the spread operator on line 8 (...syncBatch) already includes all properties from syncBatch, including sinceDaysAgo.

🔎 Proposed refactor
 export const transformSyncBatch = (
   syncBatch: SyncBatch
 ): Omit<ApiSyncBatch, "progress"> => {
   return {
     ...syncBatch,
     scheduledAt: syncBatch.scheduledAt.toISOString(),
     finishedAt: syncBatch.finishedAt?.toISOString(),
-    sinceDaysAgo: syncBatch.sinceDaysAgo,
   };
 };
apps/api/src/app/sync-batch/resolvers/queries/sync-batch-progress.query.ts (1)

6-18: Rename export to reflect that it resolves SyncBatch.progress.

The export name workspaceLastSyncBatchQuery is misleading. This resolver handles the progress field on the SyncBatch type, not a workspace query. Consider renaming to something like syncBatchProgressResolver or syncBatchFieldResolvers for clarity.

🔎 Proposed refactor
-export const workspaceLastSyncBatchQuery = createFieldResolver("SyncBatch", {
+export const syncBatchFieldResolvers = createFieldResolver("SyncBatch", {
   progress: async ({ id }) => {
apps/web/src/components/card-setting/card-setting.tsx (1)

13-20: Rename interface to match component name.

The interface is named CardOpenableSettingsProps but the component is named CardSetting. For consistency and clarity, consider renaming the interface to CardSettingProps.

🔎 Proposed refactor
-interface CardOpenableSettingsProps extends Omit<PaperProps, "left" | "right"> {
+interface CardSettingProps extends Omit<PaperProps, "left" | "right"> {
   left: React.ReactNode;
   right?: React.ReactNode;
   title: string;
   description: string;
   href?: string;
   isLoading?: boolean;
 }

 export const CardSetting = ({
   left,
   right,
   title,
   description,
   href,
   isLoading,
   ...props
-}: CardOpenableSettingsProps) => {
+}: CardSettingProps) => {
apps/web/src/api/sync-batch.api.ts (1)

64-68: Consider invalidating the sync-progress query after scheduling.

After scheduling a sync batch, the useWorkspaceLastSyncBatchQuery should refetch to show the newly scheduled batch and its progress. Currently, only ["workspace", ..., "settings"] is invalidated, but the query uses ["workspace", ..., "sync-progress"].

🔎 Proposed fix
     onSettled: (_, __, args) => {
       queryClient.invalidateQueries({
         queryKey: ["workspace", args.input.workspaceId, "settings"],
       });
+      queryClient.invalidateQueries({
+        queryKey: ["workspace", args.input.workspaceId, "sync-progress"],
+      });
     },
apps/web/src/app/settings/workspace/resync/page.tsx (2)

35-42: Aggressive polling interval may impact performance.

The 1-second polling interval could generate significant network traffic, especially for workspaces with slow sync operations. Consider using a longer interval (e.g., 3-5 seconds) or enabling polling only when isInProgress is true.

🔎 Conditional polling suggestion
   const { data: lastSyncBatchData, isLoading } = useWorkspaceLastSyncBatchQuery(
     {
       workspaceId: workspace.id,
     },
     {
-      refetchInterval: 1000,
+      refetchInterval: isInProgress ? 2000 : false,
     },
   );

Note: This requires lifting isInProgress calculation or using a separate state to track if we should poll.


56-77: Async handler doesn't need async/await with mutation callbacks.

The handleResync function uses async/await but the mutation is called with callbacks (onSuccess, onError). The await has no effect here since mutate doesn't return a promise. Either use mutateAsync with try/catch or keep mutate with callbacks but remove async/await.

🔎 Option 1: Remove unnecessary async/await
-  const handleResync = async () => {
-    await scheduleSyncBatch(
+  const handleResync = () => {
+    scheduleSyncBatch(
       {
apps/api/src/app/sync-batch/resolvers/mutations/schedule-sync-batch.mutation.ts (2)

24-24: Remove inline development note.

The comment "use date fns throughout the codebase" appears to be a development note rather than documentation. Consider removing it.

🔎 Proposed fix
-    // if last batch was scheduled less than 24 hours ago, throw an error - use date fns throughout the codebase
+    // Enforce 24-hour rate limit between sync operations

39-45: Consider adding a user-facing message for the no repositories error.

The validation error for no syncable repositories doesn't include a userFacingMessage. Based on the error provider in the frontend (lines 14-22 of error-message.provider.ts), INPUT_VALIDATION_FAILED errors display the userFacingMessage to users. Without it, users will see the generic "Validation error, please fix the input."

🔎 Proposed fix
     if (repositories.length === 0) {
       throw new InputValidationException("No syncable repositories found", {
+        userFacingMessage: "No syncable repositories found. Archived, fork, and mirror repositories are excluded.",
         validationErrors: {
           repositories: "No syncable repositories found",
         },
       });
     }
apps/api/src/app/sync-batch/services/sync-batch.service.ts (1)

18-32: Clarify/default sinceDaysAgo handling in scheduleSyncBatch

sinceDaysAgo is now required in CreateSyncBatchArgs and written straight into the DB. If any existing callers treat it as optional, this could surface as a runtime error or an unintended NULL/default at the DB layer.

Consider either:

  • Making sinceDaysAgo strictly required at the type level everywhere you call scheduleSyncBatch, or
  • Providing a safe default here, e.g.:
export const scheduleSyncBatch = async ({
  workspaceId,
  scheduledAt,
  metadata,
  sinceDaysAgo = DEFAULT_SYNC_BATCH_SINCE_DAYS_AGO,
}: CreateSyncBatchArgs) => { /* ... */ }

and still validating user-provided values (e.g., non‑negative, reasonable upper bound) in the resolver or service that constructs CreateSyncBatchArgs.

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6ce86a0 and fba08af.

📒 Files selected for processing (28)
  • apps/api/src/app/github/services/github-repository-pull-requests.service.ts
  • apps/api/src/app/github/services/github-repository.service.ts
  • apps/api/src/app/sync-batch/resolvers/mutations/schedule-sync-batch.mutation.ts
  • apps/api/src/app/sync-batch/resolvers/queries/last-sync-batch.query.ts
  • apps/api/src/app/sync-batch/resolvers/queries/sync-batch-progress.query.ts
  • apps/api/src/app/sync-batch/resolvers/transformers/sync-batch.transformer.ts
  • apps/api/src/app/sync-batch/services/sync-batch.service.ts
  • apps/api/src/app/sync-batch/services/sync-batch.types.ts
  • apps/api/src/app/sync-batch/sync-batch.schema.ts
  • apps/api/src/app/workspaces/resolvers/workspaces.schema.ts
  • apps/web/src/api/sync-batch.api.ts
  • apps/web/src/app/humans/teams/[id]/alerts/page.tsx
  • apps/web/src/app/humans/teams/[id]/health-and-performance/page.tsx
  • apps/web/src/app/humans/teams/[id]/pull-requests/page.tsx
  • apps/web/src/app/settings/components/subnav-settings/subnav-settings.tsx
  • apps/web/src/app/settings/data-ingestion/page.tsx
  • apps/web/src/app/settings/pull-request-settings/page.tsx
  • apps/web/src/app/settings/workspace/page.tsx
  • apps/web/src/app/settings/workspace/resync/page.tsx
  • apps/web/src/components/card-openable-settings/card-openable-settings.tsx
  • apps/web/src/components/card-openable-settings/index.ts
  • apps/web/src/components/card-setting/card-setting.tsx
  • apps/web/src/components/card-setting/index.ts
  • apps/web/src/components/icon-info/icon-info.tsx
  • apps/web/src/routes.tsx
  • packages/graphql-types/api.ts
  • packages/graphql-types/frontend/gql.ts
  • packages/graphql-types/frontend/graphql.ts
💤 Files with no reviewable changes (2)
  • apps/web/src/components/card-openable-settings/index.ts
  • apps/web/src/components/card-openable-settings/card-openable-settings.tsx
🧰 Additional context used
🧠 Learnings (4)
📓 Common learnings
Learnt from: waltergalvao
Repo: sweetr-dev/sweetr.dev PR: 55
File: apps/api/src/app/github/services/github-pull-request.service.ts:68-70
Timestamp: 2025-06-02T01:51:17.244Z
Learning: In the sync batch progress system, the "done" count represents "attempted sync" not "successfully completed sync". It's used for a user-facing progress bar to indicate how many PRs have been attempted, allowing users to know when they can start using the dashboard. Failed jobs get retried but don't affect the progress counter, and the early increment (after workspace lookup, before GitHub API calls) is intentional to show immediate progress to users.
Learnt from: waltergalvao
Repo: sweetr-dev/sweetr.dev PR: 55
File: apps/api/src/app/github/services/github-pull-request.service.ts:68-70
Timestamp: 2025-06-02T01:48:34.731Z
Learning: In the sync batch system, `failCount === 0` indicates the first attempt at processing a job, not that the job won't fail. The increment of "done" progress happens early in the process, after finding the workspace but before GitHub API calls that could still fail.
📚 Learning: 2025-06-02T01:48:34.731Z
Learnt from: waltergalvao
Repo: sweetr-dev/sweetr.dev PR: 55
File: apps/api/src/app/github/services/github-pull-request.service.ts:68-70
Timestamp: 2025-06-02T01:48:34.731Z
Learning: In the sync batch system, `failCount === 0` indicates the first attempt at processing a job, not that the job won't fail. The increment of "done" progress happens early in the process, after finding the workspace but before GitHub API calls that could still fail.

Applied to files:

  • apps/api/src/app/github/services/github-repository-pull-requests.service.ts
📚 Learning: 2025-06-02T01:51:17.244Z
Learnt from: waltergalvao
Repo: sweetr-dev/sweetr.dev PR: 55
File: apps/api/src/app/github/services/github-pull-request.service.ts:68-70
Timestamp: 2025-06-02T01:51:17.244Z
Learning: In the sync batch progress system, the "done" count represents "attempted sync" not "successfully completed sync". It's used for a user-facing progress bar to indicate how many PRs have been attempted, allowing users to know when they can start using the dashboard. Failed jobs get retried but don't affect the progress counter, and the early increment (after workspace lookup, before GitHub API calls) is intentional to show immediate progress to users.

Applied to files:

  • apps/api/src/app/github/services/github-repository-pull-requests.service.ts
📚 Learning: 2025-01-30T06:09:36.043Z
Learnt from: waltergalvao
Repo: sweetr-dev/sweetr.dev PR: 44
File: apps/api/src/app/integrations/resolvers/mutations/send-test-message.mutation.ts:30-30
Timestamp: 2025-01-30T06:09:36.043Z
Learning: GraphQL mutations in this codebase already handle errors and show user-facing error messages. Additional try-catch blocks in mutation resolvers are not needed as errors are properly propagated and handled at the GraphQL layer.

Applied to files:

  • apps/api/src/app/sync-batch/resolvers/mutations/schedule-sync-batch.mutation.ts
🧬 Code graph analysis (17)
apps/api/src/app/github/services/github-repository-pull-requests.service.ts (1)
apps/api/src/app/sync-batch/services/sync-batch.service.ts (1)
  • maybeFinishSyncBatch (150-191)
apps/api/src/app/sync-batch/resolvers/mutations/schedule-sync-batch.mutation.ts (6)
apps/api/src/lib/graphql.ts (1)
  • createMutationResolver (11-19)
apps/api/src/lib/logger.ts (1)
  • logger (21-76)
apps/api/src/app/billing/services/billing.service.ts (1)
  • protectWithPaywall (142-156)
apps/api/src/app/sync-batch/services/sync-batch.service.ts (4)
  • findLastSyncBatch (264-273)
  • findSyncableRepositories (253-262)
  • scheduleSyncBatch (20-42)
  • DEFAULT_SYNC_BATCH_SINCE_DAYS_AGO (18-18)
apps/api/src/app/errors/exceptions/input-validation.exception.ts (1)
  • InputValidationException (11-26)
apps/api/src/app/sync-batch/resolvers/transformers/sync-batch.transformer.ts (1)
  • transformSyncBatch (4-13)
apps/web/src/app/settings/data-ingestion/page.tsx (2)
apps/web/src/components/page-container/page-container.tsx (1)
  • PageContainer (11-29)
apps/web/src/components/breadcrumbs/breadcrumbs.tsx (1)
  • Breadcrumbs (22-67)
apps/web/src/components/icon-info/icon-info.tsx (1)
packages/graphql-types/api.ts (1)
  • Omit (11-11)
apps/web/src/app/settings/workspace/resync/page.tsx (5)
apps/web/src/api/sync-batch.api.ts (2)
  • useWorkspaceLastSyncBatchQuery (17-40)
  • useScheduleSyncBatchMutation (42-70)
apps/api/src/app/sync-batch/services/sync-batch.service.ts (1)
  • scheduleSyncBatch (20-42)
apps/web/src/providers/notification.provider.tsx (2)
  • showSuccessNotification (37-41)
  • showErrorNotification (22-26)
apps/web/src/providers/error-message.provider.ts (1)
  • getErrorMessage (4-31)
apps/web/src/providers/date.provider.ts (1)
  • formatLocaleDate (60-78)
apps/web/src/app/settings/pull-request-settings/page.tsx (2)
apps/web/src/components/card-setting/card-setting.tsx (1)
  • CardSetting (22-71)
apps/web/src/components/card-setting/index.ts (1)
  • CardSetting (1-1)
apps/api/src/app/github/services/github-repository.service.ts (1)
apps/api/src/app/sync-batch/services/sync-batch.service.ts (1)
  • DEFAULT_SYNC_BATCH_SINCE_DAYS_AGO (18-18)
apps/web/src/app/settings/workspace/page.tsx (3)
apps/web/src/api/sync-batch.api.ts (1)
  • useWorkspaceLastSyncBatchQuery (17-40)
apps/web/src/components/card-setting/card-setting.tsx (1)
  • CardSetting (22-71)
apps/web/src/providers/date.provider.ts (1)
  • formatLocaleDate (60-78)
apps/web/src/app/humans/teams/[id]/alerts/page.tsx (2)
apps/web/src/components/card-setting/card-setting.tsx (1)
  • CardSetting (22-71)
apps/web/src/components/card-setting/index.ts (1)
  • CardSetting (1-1)
apps/api/src/app/sync-batch/resolvers/transformers/sync-batch.transformer.ts (2)
packages/graphql-types/api.ts (2)
  • SyncBatch (922-934)
  • Omit (11-11)
packages/graphql-types/frontend/graphql.ts (1)
  • SyncBatch (919-931)
apps/web/src/api/sync-batch.api.ts (3)
packages/graphql-types/frontend/graphql.ts (4)
  • WorkspaceLastSyncBatchQueryVariables (1640-1642)
  • WorkspaceLastSyncBatchQuery (1645-1645)
  • ScheduleSyncBatchMutation (1652-1652)
  • MutationScheduleSyncBatchArgs (608-610)
packages/graphql-types/frontend/gql.ts (1)
  • graphql (348-350)
packages/graphql-types/api.ts (1)
  • MutationScheduleSyncBatchArgs (611-613)
apps/api/src/app/sync-batch/resolvers/queries/last-sync-batch.query.ts (5)
apps/api/src/app/sync-batch/resolvers/queries/sync-batch-progress.query.ts (1)
  • workspaceLastSyncBatchQuery (6-18)
apps/api/src/lib/graphql.ts (1)
  • createFieldResolver (21-30)
apps/api/src/lib/logger.ts (1)
  • logger (21-76)
apps/api/src/app/sync-batch/services/sync-batch.service.ts (1)
  • findLastSyncBatch (264-273)
apps/api/src/app/sync-batch/resolvers/transformers/sync-batch.transformer.ts (1)
  • transformSyncBatch (4-13)
apps/web/src/routes.tsx (1)
apps/web/src/app/settings/workspace/resync/page.tsx (1)
  • WorkspaceResyncPage (31-203)
apps/api/src/app/sync-batch/services/sync-batch.service.ts (1)
apps/api/src/prisma.ts (1)
  • getPrisma (23-49)
apps/web/src/components/card-setting/card-setting.tsx (1)
packages/graphql-types/api.ts (1)
  • Omit (11-11)
packages/graphql-types/api.ts (3)
packages/graphql-types/frontend/graphql.ts (4)
  • SyncBatch (919-931)
  • ScheduleSyncBatchInput (901-906)
  • Scalars (11-24)
  • Maybe (3-3)
apps/api/src/lib/type-helpers.ts (1)
  • DeepPartial (25-33)
packages/graphql-types/shared.ts (1)
  • GraphQLContext (7-27)
packages/graphql-types/frontend/graphql.ts (1)
packages/graphql-types/api.ts (4)
  • SyncBatch (922-934)
  • MutationScheduleSyncBatchArgs (611-613)
  • ScheduleSyncBatchInput (904-909)
  • Maybe (4-4)
🔇 Additional comments (21)
apps/web/src/app/humans/teams/[id]/health-and-performance/page.tsx (1)

9-9: Good icon choice for size measurement.

IconRuler is more semantically appropriate than IconAspectRatio for representing size distribution, as it directly conveys measurement rather than proportions.

Also applies to: 37-37

apps/web/src/app/humans/teams/[id]/pull-requests/page.tsx (1)

23-23: LGTM! Improved icon semantics.

The icon change from IconAspectRatio to IconRuler is semantically more appropriate for representing "Size" in the filter UI. This improves the visual clarity and consistency of the interface.

Also applies to: 142-142

apps/web/src/app/settings/components/subnav-settings/subnav-settings.tsx (2)

7-7: LGTM! Icon and label updates improve clarity.

The icon change from IconUsers to IconUserHexagon and the label update from "Members" to "Users" are clear cosmetic improvements that enhance the UI consistency.

Also applies to: 56-56, 63-63


31-31: Correct approach for nested route navigation.

The change from exact path matching to prefix matching with startsWith() is the right pattern for this navigation structure. Nested routes like /settings/workspace/resync are already implemented, and this change ensures parent navigation items remain highlighted when viewing child pages—exactly as intended.

The changes across lines 31, 39, 48, 68, and 76 are all consistent and appropriate.

apps/web/src/components/icon-info/icon-info.tsx (1)

7-7: LGTM! Type expansion is backward compatible.

The change to allow ReactNode in addition to string for the tooltip prop is backward compatible and aligns well with Mantine's Tooltip component, which already accepts ReactNode for its label prop. This enables richer tooltip content while maintaining existing functionality.

Also applies to: 11-11

apps/web/src/app/settings/data-ingestion/page.tsx (1)

1-27: LGTM! Clean page component implementation.

The DataIngestionPage component follows established patterns in the codebase with proper breadcrumb navigation, page container usage, and nested route support via Outlet. The structure is clean and maintainable.

apps/web/src/app/humans/teams/[id]/alerts/page.tsx (1)

5-5: LGTM! Component replacement is consistent.

The replacement of CardOpenableSettings with CardSetting is straightforward and maintains the same props and behavior. This aligns with the broader UI refactoring effort across the codebase.

Also applies to: 35-35, 63-63

apps/api/src/app/github/services/github-repository.service.ts (1)

10-13: LGTM! Good use of named constant.

Replacing a hardcoded value with DEFAULT_SYNC_BATCH_SINCE_DAYS_AGO improves maintainability and makes the default behavior explicit. The 365-day default is reasonable for syncing historical data during repository onboarding.

Also applies to: 43-43

apps/web/src/components/card-setting/index.ts (1)

1-1: LGTM! Standard barrel export pattern.

The barrel export follows the established pattern in the codebase for component exports, enabling clean imports.

apps/api/src/app/github/services/github-repository-pull-requests.service.ts (1)

16-19: LGTM! Empty result batch completion handling added.

The addition of maybeFinishSyncBatch ensures that sync batches complete properly even when no pull requests are found for a repository. This correctly handles the edge case where a repository has no PRs matching the sync criteria.

Also applies to: 48-51

apps/web/src/routes.tsx (1)

73-73: LGTM! Nested route configuration is correct.

The new /settings/workspace/resync route is properly nested under /settings/workspace, enabling the resync modal UI to be rendered as a child route.

Also applies to: 205-210

apps/api/src/app/sync-batch/resolvers/queries/last-sync-batch.query.ts (1)

7-23: LGTM! Well-structured field resolver.

The resolver correctly fetches the last sync batch for a workspace, handles the null case appropriately, and transforms the result using the dedicated transformer.

apps/web/src/app/settings/pull-request-settings/page.tsx (1)

4-4: LGTM! Component and icon updates are appropriate.

The refactor from CardOpenableSettings to CardSetting and the icon change from IconAspectRatio to IconRuler are both semantically appropriate for the "Size Calculation" setting.

Also applies to: 6-6, 19-30

apps/web/src/app/settings/workspace/page.tsx (1)

30-36: LGTM! Data ingestion UI implemented correctly.

The integration of useWorkspaceLastSyncBatchQuery and the new "Data Ingestion" section provides clear visibility into the sync status. The date formatting with formatLocaleDate and parseISO is correct, and the fallback text is appropriate. The <Outlet /> enables the nested resync route to render properly.

Also applies to: 65-95, 130-130

apps/web/src/api/sync-batch.api.ts (1)

17-40: LGTM!

The query hook is well-structured with proper typing and query key organization.

apps/web/src/app/settings/workspace/resync/page.tsx (1)

148-179: LGTM!

The in-progress state UI is well implemented with clear messaging, proper date formatting, and an animated progress bar with a minimum value for visual feedback. The tooltip showing exact percentage is a nice UX touch.

apps/api/src/app/sync-batch/resolvers/mutations/schedule-sync-batch.mutation.ts (1)

14-58: LGTM!

The mutation implementation is solid with proper paywall protection, rate limiting, input validation, and clamping of sinceDaysAgo. The use of date-fns for date comparisons and the transformer pattern are consistent with the codebase. Based on learnings, GraphQL errors are properly handled at the framework layer.

packages/graphql-types/frontend/gql.ts (1)

63-64: LGTM!

The generated GraphQL type definitions for WorkspaceLastSyncBatch query and ScheduleSyncBatch mutation are correctly added and consistent with the new API surface.

Also applies to: 283-290

packages/graphql-types/frontend/graphql.ts (1)

559-570: SyncBatch frontend schema additions look consistent and codegen-safe

The added ScheduleSyncBatchInput, SyncBatch, Workspace.lastSyncBatch, and the WorkspaceLastSyncBatch/ScheduleSyncBatch operation types and documents all line up with the backend API shapes and existing scalar conventions. Nothing stands out as inconsistent or risky here, especially given this file is generated.

Also applies to: 608-610, 901-907, 919-931, 1144-1145, 1640-1653, 1805-1806

apps/api/src/app/sync-batch/services/sync-batch.service.ts (1)

253-273: New SyncBatch helpers (findSyncableRepositories, findLastSyncBatch) are straightforward and correct

Both helpers use getPrisma(workspaceId) with explicit workspaceId predicates and reasonable filters (exclude forks, mirrors, archived repositories; pick last batch by scheduledAt desc). They fit well with the existing service style and should be easy to reuse from resolvers.

packages/graphql-types/api.ts (1)

562-573: SyncBatch GraphQL API surface and resolver typings are consistent

The additions of ScheduleSyncBatchInput, SyncBatch, Mutation.scheduleSyncBatch, and Workspace.lastSyncBatch, plus their entries in ResolversTypes, ResolversParentTypes, SyncBatchResolvers, MutationResolvers, and WorkspaceResolvers, all look coherent and match the frontend/generated types and service behavior (including non‑null progress). No mismatches or schema/typing issues stand out here. Based on learnings, this keeps existing sync‑progress semantics intact.

Also applies to: 611-614, 904-910, 922-935, 1147-1158, 1440-1445, 1550-1555, 1856-1867, 1991-1999, 2151-2163

Copy link

@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: 0

Caution

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

⚠️ Outside diff range comments (1)
apps/api/src/app/deployment/services/deployment.service.ts (1)

87-148: Fix cursor-based pagination: cursor field must align with orderBy field.

The cursor is based on id (line 94), but the ordering is now by deployedAt (line 102). This mismatch can cause pagination to skip or duplicate records when the chronological order of deployedAt differs from the id sequence.

🔎 Proposed fixes

Option 1 (Recommended): Use compound ordering with deployedAt primary and id secondary

This maintains chronological ordering while ensuring deterministic, stable pagination:

     orderBy: {
-      deployedAt: "desc",
+      deployedAt: "desc",
+      id: "desc",
     },

Note: Prisma supports arrays for orderBy to achieve compound sorting. If the current version doesn't support object notation with multiple fields, use:

-    orderBy: {
-      deployedAt: "desc",
-    },
+    orderBy: [
+      { deployedAt: "desc" },
+      { id: "desc" },
+    ],

Option 2: Revert to ID-based ordering

If chronological ordering by deployedAt isn't essential:

     orderBy: {
-      deployedAt: "desc",
+      id: "desc",
     },
🧹 Nitpick comments (2)
apps/api/src/app/sync-batch/services/sync-batch.validation.ts (1)

4-7: Consider tightening numeric constraints to integers.

Both workspaceId and sinceDaysAgo likely expect positive integers. The current schema allows decimals (e.g., sinceDaysAgo: 1.5) and non-positive values for workspaceId (e.g., 0 or -1).

🔎 Proposed fix
 export const scheduleSyncBatchValidationSchema = z.object({
-  workspaceId: z.number(),
-  sinceDaysAgo: z.number().min(1).max(DEFAULT_SYNC_BATCH_SINCE_DAYS_AGO),
+  workspaceId: z.number().int().positive(),
+  sinceDaysAgo: z.number().int().min(1).max(DEFAULT_SYNC_BATCH_SINCE_DAYS_AGO),
 });
apps/api/src/app/sync-batch/resolvers/mutations/schedule-sync-batch.mutation.ts (1)

52-60: Redundant clamping of sinceDaysAgo.

The validation schema already enforces .max(DEFAULT_SYNC_BATCH_SINCE_DAYS_AGO), making the Math.min on line 55 redundant. You could simplify to just use sinceDaysAgo directly, or keep this as intentional defense-in-depth.

🔎 Proposed simplification
     const syncBatch = await scheduleSyncBatch({
       workspaceId,
       scheduledAt: new Date(),
-      sinceDaysAgo: Math.min(sinceDaysAgo, DEFAULT_SYNC_BATCH_SINCE_DAYS_AGO),
+      sinceDaysAgo,
       metadata: {
         isOnboarding: false,
         repositories: repositories.map((repository) => repository.name),
       },
     });
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between fba08af and fe3a684.

📒 Files selected for processing (3)
  • apps/api/src/app/deployment/services/deployment.service.ts
  • apps/api/src/app/sync-batch/resolvers/mutations/schedule-sync-batch.mutation.ts
  • apps/api/src/app/sync-batch/services/sync-batch.validation.ts
🧰 Additional context used
🧠 Learnings (3)
📓 Common learnings
Learnt from: waltergalvao
Repo: sweetr-dev/sweetr.dev PR: 55
File: apps/api/src/app/github/services/github-pull-request.service.ts:68-70
Timestamp: 2025-06-02T01:51:17.244Z
Learning: In the sync batch progress system, the "done" count represents "attempted sync" not "successfully completed sync". It's used for a user-facing progress bar to indicate how many PRs have been attempted, allowing users to know when they can start using the dashboard. Failed jobs get retried but don't affect the progress counter, and the early increment (after workspace lookup, before GitHub API calls) is intentional to show immediate progress to users.
📚 Learning: 2024-12-01T02:31:20.571Z
Learnt from: waltergalvao
Repo: sweetr-dev/sweetr.dev PR: 33
File: apps/api/src/app/workspaces/services/workspace-settings.types.ts:5-11
Timestamp: 2024-12-01T02:31:20.571Z
Learning: You prefer using per-field validation in `zod` schemas (e.g., in `apps/api/src/app/workspaces/services/workspace-settings.types.ts`) over cross-field validation using `.refine()`, to allow displaying validation errors below each input in forms.

Applied to files:

  • apps/api/src/app/sync-batch/services/sync-batch.validation.ts
📚 Learning: 2025-01-30T06:09:36.043Z
Learnt from: waltergalvao
Repo: sweetr-dev/sweetr.dev PR: 44
File: apps/api/src/app/integrations/resolvers/mutations/send-test-message.mutation.ts:30-30
Timestamp: 2025-01-30T06:09:36.043Z
Learning: GraphQL mutations in this codebase already handle errors and show user-facing error messages. Additional try-catch blocks in mutation resolvers are not needed as errors are properly propagated and handled at the GraphQL layer.

Applied to files:

  • apps/api/src/app/sync-batch/resolvers/mutations/schedule-sync-batch.mutation.ts
🧬 Code graph analysis (1)
apps/api/src/app/sync-batch/services/sync-batch.validation.ts (1)
apps/api/src/app/sync-batch/services/sync-batch.service.ts (1)
  • DEFAULT_SYNC_BATCH_SINCE_DAYS_AGO (18-18)
🔇 Additional comments (2)
apps/api/src/app/sync-batch/resolvers/mutations/schedule-sync-batch.mutation.ts (2)

27-40: LGTM!

The 24-hour cooldown logic correctly prevents abuse while providing a clear user-facing error message.


16-64: LGTM!

The mutation follows a clean structure with proper validation, paywall protection, cooldown enforcement, and repository validation before scheduling. Error handling is appropriate for the GraphQL layer. Based on learnings, errors are properly propagated at the GraphQL level.

Copy link

@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: 0

🧹 Nitpick comments (2)
apps/api/src/app/sync-batch/services/sync-batch.validation.ts (1)

4-7: Consider reordering validators for better logical flow.

The validator chain .min(1).max(DEFAULT_SYNC_BATCH_SINCE_DAYS_AGO).int() is functionally correct, but conventionally type refinements like .int() are placed before range checks for clearer intent: .int().min(1).max(DEFAULT_SYNC_BATCH_SINCE_DAYS_AGO).

🔎 Proposed refactor
 export const scheduleSyncBatchValidationSchema = z.object({
   workspaceId: z.number(),
-  sinceDaysAgo: z.number().min(1).max(DEFAULT_SYNC_BATCH_SINCE_DAYS_AGO).int(),
+  sinceDaysAgo: z.number().int().min(1).max(DEFAULT_SYNC_BATCH_SINCE_DAYS_AGO),
 });
apps/web/src/app/settings/workspace/resync/page.tsx (1)

166-172: Consider the UX implications of the 10% minimum progress.

The progress bar displays Math.max(10, lastSyncBatch.progress) to ensure visibility, but this creates a discrepancy when actual progress is 0-9%. The tooltip shows the true percentage, but users might be confused seeing 10% on the bar when actual progress is lower. Consider whether this minimum is necessary, or if adding a visual indicator (e.g., pulsing animation for 0-9%) would be clearer.

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between fe3a684 and b585856.

📒 Files selected for processing (5)
  • apps/api/src/app/sync-batch/resolvers/mutations/schedule-sync-batch.mutation.ts
  • apps/api/src/app/sync-batch/resolvers/queries/sync-batch-progress.query.ts
  • apps/api/src/app/sync-batch/services/sync-batch.validation.ts
  • apps/web/src/app/settings/workspace/resync/page.tsx
  • apps/web/src/components/card-setting/card-setting.tsx
🧰 Additional context used
🧠 Learnings (3)
📓 Common learnings
Learnt from: waltergalvao
Repo: sweetr-dev/sweetr.dev PR: 55
File: apps/api/src/app/github/services/github-pull-request.service.ts:68-70
Timestamp: 2025-06-02T01:51:17.244Z
Learning: In the sync batch progress system, the "done" count represents "attempted sync" not "successfully completed sync". It's used for a user-facing progress bar to indicate how many PRs have been attempted, allowing users to know when they can start using the dashboard. Failed jobs get retried but don't affect the progress counter, and the early increment (after workspace lookup, before GitHub API calls) is intentional to show immediate progress to users.
📚 Learning: 2024-12-01T02:31:20.571Z
Learnt from: waltergalvao
Repo: sweetr-dev/sweetr.dev PR: 33
File: apps/api/src/app/workspaces/services/workspace-settings.types.ts:5-11
Timestamp: 2024-12-01T02:31:20.571Z
Learning: You prefer using per-field validation in `zod` schemas (e.g., in `apps/api/src/app/workspaces/services/workspace-settings.types.ts`) over cross-field validation using `.refine()`, to allow displaying validation errors below each input in forms.

Applied to files:

  • apps/api/src/app/sync-batch/services/sync-batch.validation.ts
📚 Learning: 2025-01-30T06:09:36.043Z
Learnt from: waltergalvao
Repo: sweetr-dev/sweetr.dev PR: 44
File: apps/api/src/app/integrations/resolvers/mutations/send-test-message.mutation.ts:30-30
Timestamp: 2025-01-30T06:09:36.043Z
Learning: GraphQL mutations in this codebase already handle errors and show user-facing error messages. Additional try-catch blocks in mutation resolvers are not needed as errors are properly propagated and handled at the GraphQL layer.

Applied to files:

  • apps/api/src/app/sync-batch/resolvers/mutations/schedule-sync-batch.mutation.ts
🧬 Code graph analysis (3)
apps/api/src/app/sync-batch/services/sync-batch.validation.ts (1)
apps/api/src/app/sync-batch/services/sync-batch.service.ts (1)
  • DEFAULT_SYNC_BATCH_SINCE_DAYS_AGO (18-18)
apps/api/src/app/sync-batch/resolvers/queries/sync-batch-progress.query.ts (3)
apps/api/src/lib/graphql.ts (1)
  • createFieldResolver (21-30)
apps/api/src/lib/logger.ts (1)
  • logger (21-76)
apps/api/src/app/sync-batch/services/sync-batch.service.ts (1)
  • getSyncBatchProgress (65-109)
apps/web/src/components/card-setting/card-setting.tsx (2)
packages/graphql-types/api.ts (1)
  • Omit (11-11)
apps/web/src/components/card-setting/index.ts (1)
  • CardSetting (1-1)
🔇 Additional comments (9)
apps/web/src/components/card-setting/card-setting.tsx (3)

1-11: LGTM!

The imports are well-organized and all necessary for the component implementation.


13-20: LGTM!

The interface is well-designed with proper type safety. Omitting left and right from PaperProps correctly avoids naming conflicts with the custom props.


22-71: LGTM! Well-structured component with good loading state handling.

The component implementation is clean and follows React best practices:

  • Loading states consistently use Skeleton components
  • Navigation is properly disabled during loading
  • Conditional Anchor wrapper provides correct semantics for clickable cards
  • Type safety is maintained throughout

The grow-on-hover CSS class (line 35) appears to be a global style. Ensure this class is defined in your global styles.

apps/api/src/app/sync-batch/resolvers/queries/sync-batch-progress.query.ts (1)

6-18: LGTM!

The resolver implementation is clean and follows established patterns. The ID validation provides appropriate error handling, and extracting only the progress field from the service response aligns with the GraphQL schema design.

apps/web/src/app/settings/workspace/resync/page.tsx (2)

35-42: Verify the 3-second polling interval is intentional.

The refetchInterval: 3000 creates a poll every 3 seconds to update the sync progress. While this provides a responsive UI, it generates frequent requests. Consider whether this interval balances UX needs with server load appropriately, or if a longer interval (e.g., 5-10 seconds) would be acceptable.


49-50: LGTM!

The isInProgress calculation correctly determines sync status based on the presence of scheduledAt and absence of finishedAt.

apps/api/src/app/sync-batch/resolvers/mutations/schedule-sync-batch.mutation.ts (3)

19-24: LGTM!

Input validation and paywall protection are correctly ordered and implemented.


26-38: LGTM!

The 24-hour cooldown logic is correctly implemented. The isAfter check properly validates that lastSyncBatch.scheduledAt is not within the last 24 hours, and provides a clear user-facing error message.


40-58: LGTM!

The repository validation and sync batch scheduling logic is well-implemented. The check for syncable repositories prevents unnecessary operations, and the metadata structure appropriately captures context with isOnboarding: false and repository names.

Copy link

@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

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b585856 and 6f80651.

📒 Files selected for processing (9)
  • apps/api/src/app/github/services/github-repository-pull-requests.service.ts
  • apps/api/src/app/github/workers/github-sync-pull-request.worker.ts
  • apps/api/src/app/sync-batch/services/sync-batch.service.ts
  • apps/api/src/app/sync-batch/sync-batch.schema.ts
  • apps/web/src/api/sync-batch.api.ts
  • apps/web/src/app/settings/workspace/page.tsx
  • apps/web/src/app/settings/workspace/resync/page.tsx
  • packages/graphql-types/api.ts
  • packages/graphql-types/frontend/graphql.ts
🚧 Files skipped from review as they are similar to previous changes (4)
  • apps/web/src/api/sync-batch.api.ts
  • apps/web/src/app/settings/workspace/page.tsx
  • apps/api/src/app/github/services/github-repository-pull-requests.service.ts
  • apps/api/src/app/sync-batch/services/sync-batch.service.ts
🧰 Additional context used
🧠 Learnings (3)
📚 Learning: 2025-06-02T01:48:34.731Z
Learnt from: waltergalvao
Repo: sweetr-dev/sweetr.dev PR: 55
File: apps/api/src/app/github/services/github-pull-request.service.ts:68-70
Timestamp: 2025-06-02T01:48:34.731Z
Learning: In the sync batch system, `failCount === 0` indicates the first attempt at processing a job, not that the job won't fail. The increment of "done" progress happens early in the process, after finding the workspace but before GitHub API calls that could still fail.

Applied to files:

  • apps/api/src/app/github/workers/github-sync-pull-request.worker.ts
📚 Learning: 2025-06-02T01:51:17.244Z
Learnt from: waltergalvao
Repo: sweetr-dev/sweetr.dev PR: 55
File: apps/api/src/app/github/services/github-pull-request.service.ts:68-70
Timestamp: 2025-06-02T01:51:17.244Z
Learning: In the sync batch progress system, the "done" count represents "attempted sync" not "successfully completed sync". It's used for a user-facing progress bar to indicate how many PRs have been attempted, allowing users to know when they can start using the dashboard. Failed jobs get retried but don't affect the progress counter, and the early increment (after workspace lookup, before GitHub API calls) is intentional to show immediate progress to users.

Applied to files:

  • apps/api/src/app/github/workers/github-sync-pull-request.worker.ts
📚 Learning: 2025-06-02T01:53:02.589Z
Learnt from: waltergalvao
Repo: sweetr-dev/sweetr.dev PR: 55
File: apps/api/src/app/github/services/github-pull-request.service.ts:68-70
Timestamp: 2025-06-02T01:53:02.589Z
Learning: In sync batch systems, when tracking "attempted" progress rather than "completed" progress, the batch completion check (maybeFinishSyncBatch) should be called immediately after incrementing progress to handle edge cases where the last item in a batch fails after progress increment but before the completion check.

Applied to files:

  • apps/api/src/app/github/workers/github-sync-pull-request.worker.ts
🧬 Code graph analysis (4)
apps/api/src/app/github/workers/github-sync-pull-request.worker.ts (1)
apps/api/src/app/sync-batch/services/sync-batch.service.ts (2)
  • incrementSyncBatchProgress (55-63)
  • maybeFinishSyncBatch (150-191)
apps/web/src/app/settings/workspace/resync/page.tsx (5)
apps/web/src/api/sync-batch.api.ts (2)
  • useWorkspaceLastSyncBatchQuery (17-40)
  • useScheduleSyncBatchMutation (42-70)
apps/api/src/app/sync-batch/services/sync-batch.service.ts (1)
  • scheduleSyncBatch (20-42)
apps/web/src/providers/notification.provider.tsx (2)
  • showSuccessNotification (37-41)
  • showErrorNotification (22-26)
apps/web/src/providers/error-message.provider.ts (1)
  • getErrorMessage (4-31)
apps/web/src/providers/date.provider.ts (1)
  • formatLocaleDate (60-78)
packages/graphql-types/frontend/graphql.ts (1)
packages/graphql-types/api.ts (5)
  • SyncBatch (922-934)
  • MutationScheduleSyncBatchArgs (611-613)
  • ScheduleSyncBatchInput (904-909)
  • Scalars (14-27)
  • Maybe (4-4)
packages/graphql-types/api.ts (3)
packages/graphql-types/frontend/graphql.ts (3)
  • SyncBatch (919-931)
  • Scalars (11-24)
  • Maybe (3-3)
apps/api/src/lib/type-helpers.ts (1)
  • DeepPartial (25-33)
packages/graphql-types/shared.ts (1)
  • GraphQLContext (7-27)
🔇 Additional comments (4)
apps/api/src/app/github/workers/github-sync-pull-request.worker.ts (1)

51-55: LGTM! Improved batch completion logic.

The change to call maybeFinishSyncBatch immediately after incrementing progress (and only on first attempts) is a good improvement. This approach:

  • Eliminates redundant batch completion checks on retries and non-batch jobs
  • Handles the edge case where the last PR in a batch fails after progress increment
  • Aligns with the batch progress model where "done" represents attempts rather than successful completions

The added comment clearly explains the intent.

Based on learnings, this implementation correctly follows the established pattern for sync batch progress tracking.

packages/graphql-types/api.ts (1)

562-573: SyncBatch GraphQL server types and resolvers are consistent and well‑wired

The new API types for ScheduleSyncBatchInput, SyncBatch, Mutation.scheduleSyncBatch, and Workspace.lastSyncBatch look internally consistent:

  • SDL shape is preserved: SyncBatch fields (id, scheduledAt, finishedAt, sinceDaysAgo, progress) and ScheduleSyncBatchInput (workspaceId, sinceDaysAgo) match the descriptions.
  • MutationScheduleSyncBatchArgs and the MutationResolvers['scheduleSyncBatch'] signature correctly require input.
  • ResolversTypes / ResolversParentTypes entries and SyncBatchResolvers / WorkspaceResolvers.lastSyncBatch follow the existing DeepPartial + wrapper patterns.

No issues from the server typing side.

Also applies to: 611-613, 904-909, 922-934, 1440-1445, 1550-1555, 1848-1857, 1991-1998, 2069-2070, 2151-2153

packages/graphql-types/frontend/graphql.ts (1)

559-570: Frontend GraphQL types and documents for sync‑batch align with the API and usage

The new sync‑batch frontend typings look solid:

  • ScheduleSyncBatchInput and SyncBatch mirror the server schema, including field names and nullability.
  • Mutation.scheduleSyncBatch and MutationScheduleSyncBatchArgs are correctly added, and Workspace.lastSyncBatch?: Maybe<SyncBatch> matches what the web app reads.
  • WorkspaceLastSyncBatchQuery selects exactly the fields used in the resync page (scheduledAt, finishedAt, sinceDaysAgo, progress), and ScheduleSyncBatchMutation returns the fields the mutation handler expects.
  • WorkspaceLastSyncBatchDocument and ScheduleSyncBatchDocument definitions correspond to those types and to the hooks wired in sync-batch.api.ts.

Everything here is coherent with the new feature and doesn’t raise any typing or shape concerns.

Also applies to: 608-612, 901-907, 919-931, 1144-1145, 1640-1653, 1805-1806

apps/api/src/app/sync-batch/sync-batch.schema.ts (1)

1-34: Sync‑batch SDL matches the type/system usage elsewhere

The SDL here cleanly introduces the sync‑batch API surface:

  • Workspace.lastSyncBatch: SyncBatch matches the generated Workspace types.
  • SyncBatch fields (id, scheduledAt, finishedAt, sinceDaysAgo, progress) and their nullability align with both server and frontend generated types.
  • scheduleSyncBatch(input: ScheduleSyncBatchInput!): SyncBatch! plus ScheduleSyncBatchInput (workspaceId, sinceDaysAgo) match the mutation/argument types in the generated code.

This SDL is consistent with the rest of the schema and the new client/server typings.

Copy link

@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: 0

♻️ Duplicate comments (1)
apps/web/src/app/settings/workspace/resync/page.tsx (1)

58-62: Critical: Remove the effect that incorrectly sets hasResynced for existing in-progress syncs.

This effect sets hasResynced = true whenever an unfinished sync batch exists, regardless of whether the user triggered it in the current session. This causes two problems:

  1. False success state: If an in-progress sync from a previous session completes while the modal is open, the success message "Resync completed successfully." displays at lines 183-192 even though the user didn't initiate it in this session.

  2. Semantic confusion: hasResynced should represent "user triggered a resync in THIS session" for preventing double-submits, not "any unfinished sync exists".

The mutation's onSuccess handler (line 75) already correctly sets hasResynced(true) when the user triggers a resync. The isInProgress flag (lines 51-52) is sufficient for gating while a batch is running.

🔎 Recommended fix
-  useEffect(() => {
-    if (lastSyncBatch && !lastSyncBatch.finishedAt) {
-      setHasResynced(true);
-    }
-  }, [lastSyncBatch]);
+  // `hasResynced` prevents multiple manual resyncs in a single session.
+  // For existing in-progress batches, we rely on `isInProgress` and backend validation.

This ensures:

  • Existing in-progress sync: isInProgress = truecanResync = false (button disabled) ✓
  • User triggers resync: onSuccess sets hasResynced = truecanResync = false after scheduling ✓
  • Success message shows only when user triggered the resync in this session ✓
🧹 Nitpick comments (1)
apps/web/src/app/settings/workspace/resync/page.tsx (1)

122-135: Consider showing when the next resync will be available.

Line 127 states "You can only resync once every 24 hours," but the UI doesn't indicate when the user can resync next if they're within the 24-hour window. This could improve UX by setting clear expectations.

You could compute and display the next available resync time based on lastSyncBatch.scheduledAt when a completed sync exists and is less than 24 hours old.

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6f80651 and dfd4c0c.

📒 Files selected for processing (1)
  • apps/web/src/app/settings/workspace/resync/page.tsx
🧰 Additional context used
🧬 Code graph analysis (1)
apps/web/src/app/settings/workspace/resync/page.tsx (5)
apps/web/src/api/sync-batch.api.ts (2)
  • useWorkspaceLastSyncBatchQuery (17-40)
  • useScheduleSyncBatchMutation (42-70)
apps/api/src/app/sync-batch/services/sync-batch.service.ts (1)
  • scheduleSyncBatch (20-42)
apps/web/src/providers/notification.provider.tsx (2)
  • showSuccessNotification (37-41)
  • showErrorNotification (22-26)
apps/web/src/providers/error-message.provider.ts (1)
  • getErrorMessage (4-31)
apps/web/src/providers/date.provider.ts (1)
  • formatLocaleDate (60-78)
🔇 Additional comments (1)
apps/web/src/app/settings/workspace/resync/page.tsx (1)

154-181: Nice progress display with minimum visual feedback.

The Math.max(10, lastSyncBatch.progress) on line 173 ensures the progress bar always shows some visual movement even in early stages (0-9%), while the tooltip displays the exact percentage. This provides good UX for ongoing operations.

@sweetr-dev sweetr-dev bot added the huge Huge PR - High risk of reviewer fatigue label Dec 24, 2025
Copy link
Contributor

@sweetrdev sweetrdev left a comment

Choose a reason for hiding this comment

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

Sweet

@waltergalvao waltergalvao merged commit 931ddf5 into main Dec 24, 2025
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

huge Huge PR - High risk of reviewer fatigue

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants