Skip to content

Conversation

shivamashtikar
Copy link
Contributor

@shivamashtikar shivamashtikar commented Sep 29, 2025

Description

  • for removing cyclic dependency created a separate PgBoss and extraction logic into dedicated modules
    • Moved PgBoss instance creation from index.ts to boss.ts
    • Updated imports to reference the new boss.ts module
    • Pulled drive‑ and collection extraction helpers out of search/utils.ts into extractors.ts
    • Removed the old helper implementations from utils.ts
    • Updated extractDriveIds to accept a getFolderItems callback to avoid circular imports
    • Improved code modularity, reduced duplication, and enhanced testability and reusability
  • add circular dependency check to dev and build workflows using https://github.com/pahen/madge
    • Introduce check-deps script using madge to detect circular imports.
    • Wire check-deps into the default dev and build npm scripts.
    • Add check-deps:unsafe variants that skip the circular dependency check for optional bypass.

Testing

  • code behavior should remain same as the changes are only intended for build fixes

Additional Notes

Summary by CodeRabbit

  • Chores

    • Added pre-run dependency checks to dev and build workflows to detect circular dependencies; optional "unsafe" scripts bypass checks.
    • Added a dev-only dependency analyzer and aligned server/frontend scripts for consistency.
    • Adjusted default database fallback URL handling.
  • Refactor

    • Centralized job-queue initialization and consolidated search/Vespa functionality into a shared service for more consistent runtime behavior and reliability.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Sep 29, 2025

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Walkthrough

Adds madge-based circular-dependency checks and unsafe script variants to frontend and server package scripts; extracts PgBoss instantiation to server/queue/boss.ts and re-exports it; centralizes Vespa client creation into server/search/vespaService.ts and updates Vespa-related modules to use the shared service.

Changes

Cohort / File(s) Summary
Frontend scripts & deps
frontend/package.json
Add check-deps script (madge); make dev and build run bun run check-deps first; add dev:unsafe and build:unsafe to skip the check; add madge to devDependencies.
Server scripts & deps
server/package.json
Add check-deps script (madge); update dev, dev:sync, and build to run check-deps first; add dev:unsafe, dev:sync-unsafe, and build:unsafe; add madge to devDependencies.
Queue: PgBoss extraction
server/queue/boss.ts, server/queue/index.ts, server/queue/toolSync.ts
New boss.ts constructs and exports configured PgBoss; index.ts re-exports boss from ./boss instead of instantiating locally; toolSync.ts removes its local boss import.
Vespa client centralization
server/search/vespaService.ts, server/search/vespa.ts, server/search/utils.ts
New vespaService.ts builds and exports sharedVespaService; vespa.ts re-exports Vespa methods bound to the shared service (adds UpdateDocument, DeleteDocument, searchCollectionRAG bindings); utils.ts switches to sharedVespaService.getFolderItems(...).
Config tweak
server/config.ts
Change default DATABASE_URL fallback to postgres://xyne:xyne@${postgresBaseHost}:5432/xyne instead of a placeholder string.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor Dev as Developer
  participant Runner as Script Runner
  participant Madge as madge (check-deps)
  participant App as App (Vite / Node)

  Dev->>Runner: run "dev" or "build"
  Runner->>Madge: run check-deps
  alt no cycles
    Madge-->>Runner: success (0)
    Runner->>App: start vite/node build/server
    App-->>Dev: running
  else cycles found
    Madge-->>Runner: fail (non-zero)
    Runner-->>Dev: exit with error
  end

  note right of Runner: "dev:unsafe" / "build:unsafe" skip Madge and start App directly
Loading
sequenceDiagram
  autonumber
  participant App as Application code
  participant VespaService as sharedVespaService
  participant Vespa as Vespa backend

  App->>VespaService: call search/insert/update helpers
  VespaService->>Vespa: forward requests to Vespa endpoint
  Vespa-->>VespaService: responses
  VespaService-->>App: return results
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • zereraz
  • kalpadhwaryu
  • junaid-shirur

Poem

I hop through imports, sniffing threads,
I stitch a boss where workers tread.
I share a Vespa, tidy and neat,
I check for cycles before we meet.
A rabbit cheers — the tree looks sweet! 🐇✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Title Check ❓ Inconclusive The title “Cyclic dependency” is related to the changeset’s main theme of addressing circular imports, but it is overly terse and does not clearly convey whether dependencies are being removed, checked, or refactored; it lacks sufficient specificity to inform a reviewer of the primary action taken. Consider revising the title to clearly state the action and scope, for example “Refactor to remove cyclic dependencies and add circular-import checks” so that the primary change and intent are explicit to reviewers.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch cyclic-dependency

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6e17514 and 07ee974.

⛔ Files ignored due to path filters (2)
  • frontend/bun.lockb is excluded by !**/bun.lockb
  • server/bun.lockb is excluded by !**/bun.lockb
📒 Files selected for processing (9)
  • frontend/package.json (2 hunks)
  • server/config.ts (1 hunks)
  • server/package.json (2 hunks)
  • server/queue/boss.ts (1 hunks)
  • server/queue/index.ts (1 hunks)
  • server/queue/toolSync.ts (0 hunks)
  • server/search/utils.ts (2 hunks)
  • server/search/vespa.ts (1 hunks)
  • server/search/vespaService.ts (1 hunks)
💤 Files with no reviewable changes (1)
  • server/queue/toolSync.ts
🚧 Files skipped from review as they are similar to previous changes (4)
  • server/search/vespaService.ts
  • server/queue/boss.ts
  • frontend/package.json
  • server/package.json
🧰 Additional context used
🧬 Code graph analysis (1)
server/search/utils.ts (1)
server/search/vespaService.ts (1)
  • sharedVespaService (51-51)
⏰ 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: build
🔇 Additional comments (9)
server/config.ts (1)

13-15: LGTM! Bug fix: Replace placeholder with proper PostgreSQL URL.

The previous fallback value "$" was clearly a placeholder that would cause connection failures. The new constructed URL provides a working default connection string for development environments.

server/search/utils.ts (2)

19-19: LGTM! Centralized Vespa service import.

The import of sharedVespaService aligns with the PR's goal to extract Vespa instantiation into a dedicated module.


89-94: LGTM; shared service export verified
Server/search/vespaService.ts correctly exports sharedVespaService via createVespaService(dependencies). Please confirm that this service API includes the getFolderItems method (e.g. by checking its type definition in @xyne/vespa-ts).

server/search/vespa.ts (5)

9-9: LGTM! Config import retained for recency decay rate.

The config import is correctly retained as it's used in the searchVespa and searchVespaAgent functions (lines 57, 83, 112).


15-15: LGTM! Centralized Vespa service as the single source.

Importing sharedVespaService as vespa successfully externalizes Vespa instantiation, eliminating circular dependencies while maintaining a clean public API.


19-24: LGTM! Method bindings maintain proper context.

The .bind(vespa) pattern ensures methods retain their correct this context when exported. This is essential for instance methods that access internal state.


117-175: Verify that all bound methods are implemented
The initial grep didn’t locate any matching definitions in the Vespa implementation—please confirm every method exported in server/search/vespa.ts (e.g. searchVespaInFiles, ifMailDocumentsExist, GetRandomDocument, etc.) is declared on the Vespa class (likely in server/search/vespaService.ts).


80-88: Verify and simplify the searchVespa call
Drop the extra .bind(vespa) and call

return await vespa.searchVespa(query, email, app, entity, {})

if searchVespa doesn’t rely on its this context; otherwise confirm that the method needs explicit binding.

server/queue/index.ts (1)

34-36: Approve external PgBoss instantiation

The boss instance is correctly initialized in server/queue/boss.ts and re-exported via server/queue/index.ts, preserving the public API and improving modularity.


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.

@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @shivamashtikar, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request primarily focuses on improving the architectural health of the application by addressing and preventing cyclic dependencies. It involves significant refactoring to decouple modules, centralize shared instances, and introduce a robust static analysis tool to enforce a cleaner dependency graph. The changes are intended to enhance code modularity, reduce duplication, and improve testability and reusability without altering existing application behavior.

Highlights

  • Cyclic Dependency Resolution: Refactored the codebase to eliminate cyclic dependencies by separating concerns into dedicated modules, improving code modularity and maintainability.
  • PgBoss Instance Centralization: Moved the PgBoss instance creation to a new boss.ts module, centralizing its definition and allowing other modules to import it without creating circular dependencies.
  • Extraction Logic Decoupling: Extracted drive and collection item extraction helpers from search/utils.ts into a new extractors.ts module, further reducing coupling and enhancing reusability.
  • Dynamic Callback for extractDriveIds: Modified the extractDriveIds function to accept getFolderItems as a callback, breaking a potential circular import chain and making the function more flexible.
  • Circular Dependency Detection: Integrated madge into the dev and build workflows for both frontend and server, adding a check-deps script to automatically detect and prevent future circular imports. unsafe variants are provided to bypass this check if necessary.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request effectively addresses cyclic dependencies by refactoring the codebase into more modular pieces, such as creating boss.ts for the PgBoss instance and extractors.ts for utility functions. The introduction of madge for automated circular dependency checks is a commendable improvement for maintaining code health. However, the review identified a few significant issues that need attention. There's a critical security risk due to hardcoded database credentials. Additionally, a critical logic bug was found in the refactored extractDriveIds function that could lead to incorrect behavior when processing Google Drive items. I've also included a couple of medium-severity suggestions to improve type safety and code clarity.

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

🧹 Nitpick comments (2)
server/package.json (1)

36-40: Strengthen madge config: resolve TS paths and ignore build outputs.

Add tsconfig resolution and exclude dist/build to avoid false positives and slow scans.

-    "check-deps": "madge --circular --extensions ts,tsx ./",
+    "check-deps": "madge --circular --extensions ts,tsx --ts-config tsconfig.json --exclude '(^|/)(dist|build|coverage)/' .",
frontend/package.json (1)

7-11: Have madge respect TS path aliases to reduce false positives.

Pass tsconfig to madge; you’re already scoping to src, so no exclude needed here.

-    "check-deps": "madge --circular --extensions ts,tsx ./src",
+    "check-deps": "madge --circular --extensions ts,tsx --ts-config tsconfig.json ./src",
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between fe95f0b and 3f506bb.

⛔ Files ignored due to path filters (2)
  • frontend/bun.lockb is excluded by !**/bun.lockb
  • server/bun.lockb is excluded by !**/bun.lockb
📒 Files selected for processing (2)
  • frontend/package.json (2 hunks)
  • server/package.json (2 hunks)
🔇 Additional comments (1)
frontend/package.json (1)

8-11: LGTM on dev/build gating with unsafe escape hatches.

The pre-check on dev/build and unsafe variants are balanced and practical.

If dev becomes noticeably slower, consider documenting when to use the unsafe variants in CONTRIBUTING.md.

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

Caution

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

⚠️ Outside diff range comments (1)
server/search/utils.ts (1)

74-117: Harden extractDriveIds: guard undefined selectedItem, tighten null checks, improve logging.

  • Possible TypeError: options.selectedItem may be undefined; current access isn’t safe.
  • Add defensive checks around folderItem shape and docId presence.
  • Log the error object + context to aid debugging.

Apply this diff:

@@
   let driveItem: string[] = []
-  if ((options.selectedItem as any)[Apps.GoogleDrive]) {
-    driveItem = [...(options.selectedItem as any)[Apps.GoogleDrive]]
-  }
+  const selected = (options as any).selectedItem
+  if (selected?.[Apps.GoogleDrive]) {
+    driveItem = [...(selected[Apps.GoogleDrive] as string[])]
+  }
@@
-        const folderItem = await sharedVespaService.getFolderItems(
+        const folderItem = await sharedVespaService.getFolderItems(
           [curr],
           fileSchema,
           DriveEntity.Folder,
           email,
         )
-        if (
-          folderItem.root &&
-          folderItem.root.children &&
-          folderItem.root.children.length > 0
-        ) {
-          for (const item of folderItem.root.children) {
+        const children = folderItem?.root?.children ?? []
+        if (children.length > 0) {
+          for (const item of children) {
             if (
-              item.fields &&
-              (item.fields as any).entity === DriveEntity.Folder
+              item?.fields &&
+              (item.fields as any).entity === DriveEntity.Folder
             ) {
-              driveItem.push((item.fields as any).docId)
+              const id = (item.fields as any).docId
+              if (id) driveItem.push(id)
             } else {
-              driveIds.push((item.fields as any).docId)
+              const id = (item.fields as any).docId
+              if (id) driveIds.push(id)
             }
           }
         }
       } catch (error) {
-        Logger.error("failed to fetch drive items")
+        Logger.error({ err: error, curr, email }, "failed to fetch drive items")
       }
🧹 Nitpick comments (1)
server/search/vespaService.ts (1)

50-51: Add a small factory for testability (non-breaking).

A helper to create isolated instances with overrides makes unit/integration tests and future multi‑tenant scenarios easier, while keeping the shared singleton for app code.

 // Create a single shared vespa service instance
 export const sharedVespaService = createVespaService(dependencies)
+
+// Factory for tests/overrides without touching the app-wide singleton.
+export const createTestVespaService = (
+  overrides: Partial<VespaDependencies> = {},
+) => createVespaService({ ...dependencies, ...overrides })
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 171a9ff and 6e17514.

⛔ Files ignored due to path filters (2)
  • frontend/bun.lockb is excluded by !**/bun.lockb
  • server/bun.lockb is excluded by !**/bun.lockb
📒 Files selected for processing (8)
  • frontend/package.json (2 hunks)
  • server/package.json (2 hunks)
  • server/queue/boss.ts (1 hunks)
  • server/queue/index.ts (1 hunks)
  • server/queue/toolSync.ts (0 hunks)
  • server/search/utils.ts (2 hunks)
  • server/search/vespa.ts (1 hunks)
  • server/search/vespaService.ts (1 hunks)
💤 Files with no reviewable changes (1)
  • server/queue/toolSync.ts
🚧 Files skipped from review as they are similar to previous changes (5)
  • server/queue/boss.ts
  • server/queue/index.ts
  • server/search/vespa.ts
  • frontend/package.json
  • server/package.json
🧰 Additional context used
🧬 Code graph analysis (2)
server/search/vespaService.ts (2)
server/logger/index.ts (2)
  • getLogger (36-93)
  • Subsystem (15-15)
server/config.ts (2)
  • NAMESPACE (15-15)
  • CLUSTER (16-16)
server/search/utils.ts (1)
server/search/vespaService.ts (1)
  • sharedVespaService (51-51)
🔇 Additional comments (2)
server/search/utils.ts (1)

19-19: Consolidation to shared service looks good.

Nice step toward removing cycles and improving reuse. Please confirm madge still reports no cycles with this new import path.

server/search/vespaService.ts (1)

22-30: createDefaultConfig and dependencies usage verified
createDefaultConfig from @xyne/vespa-ts v1.0.5 accepts a Partial and your overrides match its expected shape. VespaDependencies require logger, config, vespaEndpoint, and optional sourceSchemas, which align with your implementation.

devesh-juspay
devesh-juspay previously approved these changes Sep 30, 2025
- Introduce `check-deps` script using madge to detect circular imports.
- Wire `check-deps` into the default `dev` and `build` npm scripts.
- Add `check-deps:unsafe` variants that skip the circular dependency check for optional bypass.
- Extract PgBoss queue client into `boss.ts` and replace duplicated configuration in `queue/index.ts` and other files with a single exported instance.
- Create `vespaService.ts` that provides a shared Vespa service, imported by `search/vespa.ts` and `search/utils.ts`.
- Remove repeated configuration and schema imports across modules.
- Simplify dependency management and reduce code duplication throughout the server.
- Replace placeholder DB URL in config.ts with real Postgres connection string
- Expose getDatabaseUrl() to provide the connection string
- Update boss.ts to use getDatabaseUrl() instead of hard‑coded URL
- Keeps queue configuration DRY and provides a single source of truth for the DB URL
@shivamashtikar shivamashtikar merged commit 1936343 into main Oct 1, 2025
3 of 4 checks passed
@shivamashtikar shivamashtikar deleted the cyclic-dependency branch October 1, 2025 09:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants