Thanks to visit codestin.com
Credit goes to github.com

Skip to content

transport 2.0 knowledgebase to 3.0#6808

Merged
uuganaa1007 merged 3 commits intomainfrom
knowledgebase
Jan 13, 2026
Merged

transport 2.0 knowledgebase to 3.0#6808
uuganaa1007 merged 3 commits intomainfrom
knowledgebase

Conversation

@Batuktech
Copy link
Collaborator

@Batuktech Batuktech commented Jan 12, 2026

Important

Integrates a comprehensive knowledge base system with articles, categories, and topics into the existing codebase, including models, GraphQL schemas, queries, and mutations.

  • Knowledge Base Integration:
    • Adds KnowledgeBaseArticle, KnowledgeBaseCategory, and KnowledgeBaseTopic models with CRUD operations in db/models/Article.ts, db/models/Category.ts, and db/models/Topic.ts.
    • Introduces GraphQL types, queries, and mutations for knowledge base entities in graphql/schemas/knowledgeBaseTypeDefs.ts, graphql/resolvers/queries/knowledgeBaseQueries.ts, and graphql/resolvers/mutations/knowledgeBaseMutations.ts.
    • Implements custom resolvers for articles, categories, and topics in graphql/resolvers/customResolvers/article.ts, category.ts, and topic.ts.
  • Schema and Resolvers Update:
    • Updates schema.ts, mutations.ts, queries.ts, and resolvers.ts to include knowledge base entities.
    • Modifies typeDefs.ts to integrate new types, queries, and mutations.
  • Database and Utility Enhancements:
    • Defines schemas for articles, categories, and topics in db/definitions/article.ts, category.ts, and topic.ts.
    • Adds utility functions in db/utils.ts for schema field handling.
    • Introduces constants for publish statuses in db/definitions/constant.ts and module names in utils/constants.ts.

This description was created by Ellipsis for dab440f. You can customize this summary. It will automatically update as commits are pushed.


Summary by CodeRabbit

  • New Features

    • Added Knowledge Base module with support for managing articles, categories, and topics
    • Enabled article creation with scheduling, reactions, view tracking, and PDF attachments
    • Implemented hierarchical category organization with parent-child relationships
    • Added article search, filtering, and pagination capabilities
    • Introduced publication status management (draft, publish, scheduled)
  • Chores

    • Extended database models and GraphQL resolvers to integrate Instagram-related entities

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

Copy link

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

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

Sorry @Batuktech, you have reached your weekly rate limit of 500000 diff characters.

Please try again later or upgrade to continue using Sourcery

Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

Your free trial has ended. If you'd like to continue receiving code reviews, you can add a payment method here.

@coderabbitai
Copy link

coderabbitai bot commented Jan 12, 2026

📝 Walkthrough

Walkthrough

This pull request introduces a comprehensive KnowledgeBase module to the GraphQL backend, including TypeScript type definitions, Mongoose database schemas and models, GraphQL resolvers for queries and mutations, and custom field resolvers. The implementation is integrated into the main Apollo schema configuration and connection resolvers, extending the API's data layer to support Articles, Categories, and Topics with full CRUD operations, filtering, and relationship resolution.

Changes

Cohort / File(s) Summary
GraphQL Schema Integration
backend/plugins/frontline_api/src/apollo/schema/schema.ts, backend/plugins/frontline_api/src/apollo/resolvers/{mutations,queries,resolvers}.ts
Extends GraphQL schema types, queries, and mutations by importing and spreading KnowledgeBase resolvers (KnowledgeBaseArticle, KnowledgeBaseCategory, KnowledgeBaseParentCategory, KnowledgeBaseTopic) and corresponding mutation/query definitions into the main Apollo configuration.
Type Definitions
backend/plugins/frontline_api/src/modules/knowledgebase/@types/{article,category,topic,common}.ts
Defines TypeScript interfaces for KnowledgeBase entities (IArticle, ICategory, ITopic, IArticleDocument, ICategoryDocument, ITopicDocument) and shared metadata (ICommonFields) to enforce type safety across the module.
Database Schemas
backend/plugins/frontline_api/src/modules/knowledgebase/db/definitions/{article,category,topic}.ts, backend/plugins/frontline_api/src/modules/knowledgebase/db/definitions/constant.ts
Defines Mongoose schemas for Articles, Categories, and Topics with field definitions, timestamps, and sparse unique indexes on code fields. Introduces PUBLISH_STATUSES constant for article workflow states.
Database Models & CRUD
backend/plugins/frontline_api/src/modules/knowledgebase/db/models/{Article,Category,Topic}.ts
Implements loadArticleClass, loadCategoryClass, and loadTopicClass factory functions that attach static methods to Mongoose schemas for getArticle, createDoc, updateDoc, removeDoc, with business logic including parent-child constraint validation for categories and cascading deletion.
Database Utilities
backend/plugins/frontline_api/src/modules/knowledgebase/db/utils.ts
Provides field() schema field builder with validation regex and auto-ID generation via nanoid, and schemaWrapper() to extend schemas with scopeBrandIds array.
GraphQL Queries
backend/plugins/frontline_api/src/modules/knowledgebase/graphql/resolvers/queries/knowledgeBaseQueries.ts
Implements 11 query resolvers for fetching articles, categories, and topics with buildQuery helper supporting filters (status, search, brand, category/article/topic IDs), dynamic sorting, and pagination via defaultPaginate.
GraphQL Mutations
backend/plugins/frontline_api/src/modules/knowledgebase/graphql/resolvers/mutations/knowledgeBaseMutations.ts
Implements Add/Edit/Remove mutations for topics, categories, and articles with validation (e.g., scheduled articles require future scheduledDate), view count increment resolver, and automatic timestamp/user tracking via model methods.
GraphQL Custom Resolvers
backend/plugins/frontline_api/src/modules/knowledgebase/graphql/resolvers/customResolvers/{article,category,topic}.ts
Defines field-level resolvers for nested data: Article resolves createdUser/publishedUser references; Category resolves articles, authors, firstTopic, numOfArticles, and childrens (for parent categories); Topic resolves brand reference, categories, parentCategories, and color.
GraphQL Type Definitions
backend/plugins/frontline_api/src/modules/knowledgebase/graphql/schemas/knowledgeBaseTypeDefs.ts
Exports SDL strings for types, queries, and mutations defining GraphQL object types (KnowledgeBaseArticle, KnowledgeBaseCategory, KnowledgeBaseTopic), input types, and 20+ resolver stubs for schema composition.
Module Constants & Utilities
backend/plugins/frontline_api/src/modules/knowledgebase/utils/constants.ts
Defines MODULE_NAMES mapping for KnowledgeBase entity identifiers (KB_TOPIC, KB_CATEGORY, KB_ARTICLE).
Connection Resolvers & Model Registry
backend/plugins/frontline_api/src/connectionResolvers.ts
Extends IModels interface with Article, Category, Topic knowledgebase models and registers corresponding load functions (loadArticleClass, loadCategoryClass, loadTopicClass). Adds Instagram model registrations and removes FacebookBots from public interface. Updates imports to include knowledgebase and Instagram types.
Minor Formatting
backend/plugins/frontline_api/src/apollo/typeDefs.ts
Adds two trailing blank lines for formatting consistency.

Sequence Diagram

sequenceDiagram
    participant Client
    participant GraphQLResolver
    participant ArticleModel
    participant Database
    participant IContext

    Client->>GraphQLResolver: knowledgeBaseArticles(args)
    GraphQLResolver->>GraphQLResolver: buildQuery(args)
    GraphQLResolver->>IContext: extract models
    GraphQLResolver->>ArticleModel: find(query)
    ArticleModel->>Database: MongoDB query
    Database-->>ArticleModel: articles[]
    ArticleModel-->>GraphQLResolver: articles[]
    GraphQLResolver->>GraphQLResolver: apply pagination
    GraphQLResolver-->>Client: paginated articles

    Client->>GraphQLResolver: knowledgeBaseArticlesAdd(input)
    GraphQLResolver->>IContext: extract models, userId
    GraphQLResolver->>ArticleModel: createDoc(input, userId)
    ArticleModel->>ArticleModel: set createdBy, createdDate
    ArticleModel->>ArticleModel: set publishedAt if status=PUBLISH
    ArticleModel->>Database: insert document
    Database-->>ArticleModel: created article
    ArticleModel-->>GraphQLResolver: IArticleDocument
    GraphQLResolver-->>Client: created article
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐰 Hops with joy at knowledge gained!
Types and schemas, beautifully chained,
Topics, articles, categories align,
GraphQL queries resolve divine!
A burrow of wisdom, now redesigned! 🏠✨

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'transport 2.0 knowledgebase to 3.0' clearly describes the main objective of this PR, which is to migrate/port the Knowledge Base module from version 2.0 to version 3.0, matching the substantial changeset.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

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

✨ Finishing touches
  • 📝 Generate docstrings

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
Contributor

@ellipsis-dev ellipsis-dev bot left a comment

Choose a reason for hiding this comment

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

Caution

Changes requested ❌

Reviewed everything up to 17670ab in 2 minutes and 59 seconds. Click for details.
  • Reviewed 1557 lines of code in 25 files
  • Skipped 0 files when reviewing.
  • Skipped posting 10 draft comments. View those below.
  • Modify your settings and rules to customize what types of comments Ellipsis leaves. And don't forget to react with 👍 or 👎 to teach Ellipsis.
1. backend/plugins/frontline_api/src/modules/knowledgebase/db/definitions/category.ts:2
  • Draft comment:
    Use the knowledgebase utils for 'field' instead of the call/integrations util for consistency.
  • Reason this comment was not posted:
    Decided after close inspection that this draft comment was likely wrong and/or not actionable: usefulness confidence = 35% vs. threshold = 50% This comment is about code organization and module boundaries. The file is in the knowledgebase module but imports from the call/integrations module. This could be a legitimate architectural concern - modules should generally use their own utilities rather than reaching into other modules. However, I need to consider: 1) Does the knowledgebase utils file actually exist and export a field function? 2) Is this a shared utility that's meant to be used across modules? Without seeing the actual codebase structure, I cannot be 100% certain that '/modules/knowledgebase/db/utils' exists or that it exports the same field function. The comment makes an assumption that may not be correct. I cannot verify from the diff alone whether '/modules/knowledgebase/db/utils' actually exists or exports a field function. The comment assumes this path exists and is the correct one to use, but this might not be true. The field utility from call/integrations might be a shared utility that's intentionally used across multiple modules. While I can't verify the existence of the suggested import path, the comment does raise a valid architectural concern about module boundaries and consistency. If the knowledgebase module should have its own utils, this is a reasonable suggestion. However, without strong evidence that the suggested path exists and is correct, this comment is speculative. The comment makes a reasonable suggestion about code organization but is speculative without verification that the suggested import path exists and exports the same field function. Since I cannot verify this from the diff alone and the rule states to only keep comments with strong evidence, this should be deleted.
2. backend/plugins/frontline_api/src/modules/knowledgebase/db/definitions/topic.ts:2
  • Draft comment:
    Import 'field' and 'schemaWrapper' from '~/modules/knowledgebase/db/utils' for consistency.
  • Reason this comment was not posted:
    Decided after close inspection that this draft comment was likely wrong and/or not actionable: usefulness confidence = 15% vs. threshold = 50% This comment is suggesting a change to the import path for consistency reasons. However, I don't have evidence that ~/modules/knowledgebase/db/utils actually exists or exports these same utilities. The current code imports from ~/modules/integrations/call/db/utils, which might be the correct and only location for these shared utilities. Without seeing the actual file structure and knowing whether the knowledgebase module has its own utils file with these exports, this comment is speculative. The comment assumes there should be a knowledgebase-specific utils file, but this might not exist. Cross-module imports are common and often intentional when sharing utilities. I might be missing that there actually is a ~/modules/knowledgebase/db/utils file that exports the same utilities, and the author simply used the wrong import path. The comment could be pointing out a real inconsistency if other files in the knowledgebase module use the knowledgebase utils. While it's possible that a knowledgebase utils file exists, I have no evidence of this from the diff or context provided. The comment is making an assumption without strong evidence. If the knowledgebase utils doesn't exist or doesn't export these functions, this comment would be incorrect and would break the code. This violates the principle that I need STRONG EVIDENCE to keep a comment. This comment should be deleted because it's speculative and lacks strong evidence. Without confirmation that ~/modules/knowledgebase/db/utils exists and exports the required functions, suggesting this change could break the code. Cross-module imports are common and often intentional.
3. backend/plugins/frontline_api/src/modules/knowledgebase/graphql/resolvers/customResolvers/topic.ts:19
  • Draft comment:
    The 'categories' resolver uses models.Topic.find; it should use models.Category.find to get categories for the topic.
  • Reason this comment was not posted:
    Decided after close inspection that this draft comment was likely wrong and/or not actionable: usefulness confidence = 20% vs. threshold = 50% The comment seems plausible - a resolver called "categories" on a Topic object would typically return Category objects, not Topic objects. However, I notice that BOTH the categories and parentCategories resolvers use models.Topic.find. This could mean: (1) both are wrong, (2) there's a hierarchical structure where Topics can have child Topics that act as categories, or (3) the naming is confusing but intentional. The query uses topicId: topic._id which suggests looking for children of this topic. Without seeing the schema definition or the Category model, I cannot be certain this is a bug. The fact that both resolvers use the same pattern makes me less confident this is an error. I don't have access to the GraphQL schema to see what these resolvers should return, nor do I have access to the models to understand the data structure. The consistent use of models.Topic.find in both resolvers might indicate this is intentional - perhaps Topics have a hierarchical structure. I'm making an assumption about what the code should do without sufficient evidence. While the comment seems reasonable on the surface, the consistent pattern across both resolvers and the lack of schema context means I cannot verify this is actually a bug. The rules state I need STRONG EVIDENCE to keep a comment, and I should delete if understanding requires more context from other files. I should delete this comment because I cannot verify it's correct without seeing the GraphQL schema, the models definitions, and understanding the intended data structure. The consistent use of models.Topic.find in both category-related resolvers suggests this might be intentional.
4. backend/plugins/frontline_api/src/apollo/resolvers/queries.ts:16
  • Draft comment:
    Typo: Missing semicolon at the end of the import statement for knowledgeBaseQueries.
  • Reason this comment was not posted:
    Decided after close inspection that this draft comment was likely wrong and/or not actionable: usefulness confidence = 30% vs. threshold = 50% The comment is about a change made in the diff (the new import on line 16). It's pointing out a legitimate inconsistency - all other imports have semicolons, but this new one doesn't. However, I need to consider the rules: "Do NOT comment on anything that would be obviously caught by the build" and "Do NOT comment unless there is clearly a code change required." The missing semicolon might be caught by a linter or build process. In TypeScript/JavaScript, semicolons are often optional (ASI - Automatic Semicolon Insertion), so this might not cause a build failure. But it is a style inconsistency within the same file. The comment is actionable and clear - just add a semicolon. This seems like a valid code quality/consistency comment. This could be caught by a linter like ESLint if the project has semicolon rules configured. If the build process includes linting, this would be automatically caught and wouldn't need a manual comment. Also, in modern JavaScript/TypeScript, semicolons are often optional, so this might not even be an error. While linters might catch this, the comment is about maintaining consistency within the file itself - all 15 other imports have semicolons. This is a clear, actionable style consistency issue that improves code quality. However, the rule states "Do NOT comment on anything that would be obviously caught by the build" - and if this project has ESLint with semicolon rules, this would definitely be caught. This is a borderline case. The comment is technically correct and actionable, pointing out a style inconsistency. However, it's likely to be caught by linting tools during the build process, which means it falls under the rule of not commenting on things that would be obviously caught by the build. I'll lean toward deleting it.
5. backend/plugins/frontline_api/src/modules/knowledgebase/db/models/Article.ts:77
  • Draft comment:
    Typographical note: The error message on this line ('Article not found') is missing a terminating semicolon. Consider adding it for consistency (e.g., throw new Error('Article not found');).
  • Reason this comment was not posted:
    Decided after close inspection that this draft comment was likely wrong and/or not actionable: usefulness confidence = 20% vs. threshold = 50% This is a stylistic/consistency issue about a missing semicolon. While it's technically correct that the semicolon is missing and inconsistent with other throw statements in the same file, I need to consider: 1) Is this something that would be caught by linting/build tools? Likely yes, if the project uses ESLint or similar. 2) Is this an "obvious or unimportant" comment? It's quite minor. 3) Does it require a code change? It's purely stylistic - JavaScript doesn't require semicolons due to ASI (Automatic Semicolon Insertion). 4) The rules say "Do NOT comment unless there is clearly a code change required" and "Do NOT make comments that are obvious or unimportant." This seems to fall into both categories - it's not a required change (the code works fine without it) and it's relatively unimportant/obvious. However, consistency in code style is valuable, and this comment does point out a real inconsistency within the same file. The other throw statements all have semicolons, so this could be considered a legitimate style issue that improves code quality. It's also actionable and clear. While consistency is valuable, this is exactly the type of issue that automated linting tools catch. The rules explicitly state not to comment on things that would be "obviously caught by the build" and to avoid "obvious or unimportant" comments. A missing semicolon in JavaScript/TypeScript is typically handled by linters and is not a functional issue. This comment should be deleted. It's a minor stylistic issue about a missing semicolon that would typically be caught by linting tools, and it falls under "obvious or unimportant" comments that should be avoided.
6. backend/plugins/frontline_api/src/modules/knowledgebase/db/models/Category.ts:73
  • Draft comment:
    Typo: The error message reads "Cannot change category. this is parent tag". Consider capitalizing "this" to start a new sentence: "Cannot change category. This is parent tag".
  • Reason this comment was not posted:
    Decided after close inspection that this draft comment was likely wrong and/or not actionable: usefulness confidence = 20% vs. threshold = 50% This is a very minor typo fix in an error message. While it is technically correct that "this" should be capitalized, this falls under the category of "obvious or unimportant" comments. Error messages with minor grammatical issues don't affect functionality, and this is a very trivial change. The rules explicitly state "Do NOT make comments that are obvious or unimportant." A capitalization issue in an error message that will rarely be seen by end users is quite minor. Additionally, the error message itself seems a bit unclear ("this is parent tag" could be better phrased as "this is a parent category" or similar), but the comment only addresses the capitalization, not the clarity of the message. While the comment is technically correct about the grammatical error, it could be argued that maintaining proper grammar in user-facing error messages is important for professionalism and clarity. Some teams have strict standards for error message quality. Even if some teams value proper grammar in error messages, this comment is still too minor and obvious to warrant a PR comment. The rules explicitly state not to make obvious or unimportant comments, and a simple capitalization fix clearly falls into that category. If this were a more significant issue with the error message (like unclear wording), it might be worth commenting on. This comment should be deleted because it's too minor and obvious. It's pointing out a simple capitalization error in an error message, which falls under "obvious or unimportant" comments that should not be made according to the rules.
7. backend/plugins/frontline_api/src/modules/knowledgebase/graphql/resolvers/customResolvers/category.ts:68
  • Draft comment:
    Typo: The function name "childrens" likely should be "children". Consider renaming it to correct the plural form.
  • Reason this comment was not posted:
    Decided after close inspection that this draft comment was likely wrong and/or not actionable: usefulness confidence = 20% vs. threshold = 50% This is tricky. While "childrens" is grammatically incorrect, in GraphQL resolvers, the function names must match the schema field names exactly. Without seeing the GraphQL schema definition, I cannot be certain whether this is actually a typo or an intentional match to an existing schema field. The comment suggests renaming, but if this is matching a schema field name, renaming just the resolver would break the code. The rules state I should only keep comments with STRONG EVIDENCE that they are correct, and if understanding requires more context (like seeing the schema), I should delete it. This definitely requires seeing the GraphQL schema to know if it's truly a typo or intentional. The comment might be correct if the schema also has this typo and both should be fixed together. However, without seeing the schema, I'm making assumptions. The author may have intentionally used "childrens" to match an existing API contract that cannot be changed. Given that I cannot see the GraphQL schema and don't have strong evidence that this is definitely wrong (it could be matching an existing schema field), and the rules explicitly state to delete comments when understanding requires more context from other files, I should delete this comment. Delete this comment. While "childrens" is grammatically incorrect, this is a GraphQL resolver where function names must match schema field names. Without seeing the schema definition, there's no strong evidence this is actually a bug rather than an intentional match to an existing field name.
8. backend/plugins/frontline_api/src/modules/knowledgebase/graphql/resolvers/mutations/knowledgeBaseMutations.ts:35
  • Draft comment:
    There's an extraneous semicolon here that doesn't seem to serve any purpose. Please remove it.
  • Reason this comment was not posted:
    Decided after close inspection that this draft comment was likely wrong and/or not actionable: usefulness confidence = 30% vs. threshold = 50% This is a code quality issue - an extraneous semicolon on its own line. While this won't cause a runtime error in JavaScript/TypeScript (it's a valid empty statement), it's clearly unintentional and reduces code quality. The comment is actionable (remove the semicolon), clear, and about code that was added in this diff. However, I need to consider: 1) Would this be caught by a linter? Most linters would flag this. 2) Is this "obvious or unimportant"? It's a minor style issue. 3) The rules say "Do NOT comment on anything that would be obviously caught by the build" - but linters aren't always part of the build. This is a borderline case. This is likely something that would be caught by a linter like ESLint with the no-extra-semi rule enabled. If the project has proper linting configured, this would be automatically flagged. The comment might be considered "obvious" since it's just a stray semicolon that doesn't affect functionality. While linters often catch this, not all projects have comprehensive linting rules enabled, and this is a legitimate code quality issue that was introduced in the new code. The comment is actionable and clear. However, given the rules emphasize not commenting on things that would be "obviously caught by the build" and this is a very minor style issue, it's borderline whether this should be kept. This comment identifies a real but minor code quality issue (extraneous semicolon). While it's actionable and correct, it's likely something that would be caught by a linter and falls into the category of minor/obvious issues. Given the strict rules about not commenting on obvious things or things caught by build tools, I'll lean toward removing this comment.
9. backend/plugins/frontline_api/src/modules/knowledgebase/graphql/resolvers/mutations/knowledgeBaseMutations.ts:108
  • Draft comment:
    Typographical suggestion: In the error message 'Scheduled Date can not be in the past !', consider using 'cannot' (one word) and removing the extra space before the exclamation mark.
  • Reason this comment was not posted:
    Decided after close inspection that this draft comment was likely wrong and/or not actionable: usefulness confidence = 20% vs. threshold = 50% This is a purely stylistic/typographical comment about error message formatting. While the suggestion is technically correct (cannot is more standard than "can not", and the space before the exclamation mark is unusual), this falls under "obvious or unimportant" comments. The rules explicitly state "Do NOT make comments that are obvious or unimportant." Error message typos or minor formatting issues are typically not critical code quality issues. The message is still perfectly understandable to users. This is the kind of nitpicky comment that doesn't provide significant value and could be caught in a general code review or linting process. However, one could argue that user-facing error messages should be polished and professional, and fixing typos improves code quality. The comment is actionable and clear, which the rules say is good for code quality refactors. Also, this appears twice in the code, so fixing it would improve consistency. While user-facing messages should be professional, this is an extremely minor stylistic issue that doesn't affect functionality or clarity. The rules emphasize not making "obvious or unimportant" comments, and a spacing/contraction preference clearly falls into this category. This is the type of nitpick that adds noise to a PR review without substantial value. This comment should be deleted. It's a minor typographical suggestion that falls under "obvious or unimportant" comments. While technically correct, it doesn't represent a meaningful code quality issue or bug that needs to be addressed.
10. backend/plugins/frontline_api/src/modules/knowledgebase/graphql/resolvers/mutations/knowledgeBaseMutations.ts:131
  • Draft comment:
    Typographical suggestion: In the error message 'Scheduled Date can not be in the past !', consider using 'cannot' (one word) and removing the extra space before the exclamation mark.
  • Reason this comment was not posted:
    Decided after close inspection that this draft comment was likely wrong and/or not actionable: usefulness confidence = 10% vs. threshold = 50% This is a purely stylistic/typographical comment about error message formatting. While the suggestion is technically correct (grammar guides prefer "cannot" over "can not" in most contexts, and the extra space before the exclamation mark is unconventional), this falls into the category of minor, unimportant comments. The rules explicitly state "Do NOT make comments that are obvious or unimportant" and "Do NOT comment unless there is clearly a code change required." A typo or minor formatting issue in an error message doesn't constitute a required code change - the code functions correctly as-is. This is the kind of nitpicky comment that doesn't add significant value to the review. Could this be considered a code quality improvement that makes error messages more professional and consistent? Some teams do care about consistent error message formatting, and this could be seen as improving user experience. While consistency in error messages can be valuable, this is such a minor stylistic point that it doesn't meet the threshold of "clearly a code change required." The error message is perfectly understandable as written, and fixing this typo doesn't materially improve the code's functionality or maintainability. This is the type of obvious, unimportant comment the rules explicitly warn against. This comment should be deleted. It's a minor typographical suggestion that doesn't constitute a required code change. The error message is functional and understandable as-is, making this an unimportant, nitpicky comment that violates the rule against obvious or unimportant feedback.

Workflow ID: wflow_ICp7bo9dfD7hzaV8

You can customize Ellipsis by changing your verbosity settings, reacting with 👍 or 👎, replying to comments, or adding code review rules.


return await models.Article.findOneAndUpdate(
{ _id },
{$set: doc}
Copy link
Contributor

Choose a reason for hiding this comment

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

Consider adding the { new: true } option to findOneAndUpdate to return the updated document.

Suggested change
{$set: doc}
{$set: doc}, { new: true }

}

await models.Category.deleteMany({
categoryId: _id
Copy link
Contributor

Choose a reason for hiding this comment

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

Use parentCategoryId (not categoryId) in the deleteMany filter when removing child categories.

Suggested change
categoryId: _id
parentCategoryId: _id

query.status = status;
}

return models.Category.find(query).sort({
Copy link
Contributor

Choose a reason for hiding this comment

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

The articles resolver is querying models.Category instead of models.Article. It should fetch articles for the category.

Suggested change
return models.Category.find(query).sort({
return models.Article.find(query).sort({

},

async firstTopic(category: ICategoryDocument, _args, { models }: IContext) {
return models.Category.findOne({ _id: category.topicId });
Copy link
Contributor

Choose a reason for hiding this comment

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

The firstTopic resolver queries models.Category; it should query models.Topic to retrieve the related topic.

Suggested change
return models.Category.findOne({ _id: category.topicId });
return models.Topic.findOne({ _id: category.topicId });

user._id
);

;
Copy link
Contributor

Choose a reason for hiding this comment

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

Remove the stray semicolon in the knowledgeBaseTopicsEdit mutation.

Suggested change
;

throw new Error('Topic not found');
}

const categories = await models.Topic.find({
Copy link
Contributor

Choose a reason for hiding this comment

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

In removeDoc, the query uses models.Topic.find({ topicId: _id }). It likely should query models.Category to remove categories under the topic.

import { widgetMutations } from '@/inbox/graphql/resolvers/mutations/widget';
import { ticketConfigMutations } from '~/modules/ticket/graphql/resolvers/mutations/ticketConfig';
import { responseTemplateMutations } from '~/modules/response/graphql/responseTemplateMutations';
import { knowledgeBaseMutations } from '@/knowledgebase/graphql/resolvers/mutations/knowledgeBaseMutations'
Copy link
Contributor

Choose a reason for hiding this comment

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

The import statement is missing a semicolon at the end. Add a semicolon for consistency with the other import statements.

Suggested change
import { knowledgeBaseMutations } from '@/knowledgebase/graphql/resolvers/mutations/knowledgeBaseMutations'
import { knowledgeBaseMutations } from '@/knowledgebase/graphql/resolvers/mutations/knowledgeBaseMutations';

authors: [User]
numOfArticles(status: String): Float

childrens: [KnowledgeBaseCategory]
Copy link
Contributor

Choose a reason for hiding this comment

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

Typo: Consider renaming 'childrens' to 'children' for proper pluralization.

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

🤖 Fix all issues with AI agents
In
@backend/plugins/frontline_api/src/modules/knowledgebase/db/definitions/category.ts:
- Line 2: The file imports the shared utility 'field' from the integrations/call
module instead of the knowledgebase module; update the import in category.ts to
use the knowledgebase module's db utils implementation of 'field' (replace the
current integrations/call import with the knowledgebase db/utils import) so the
knowledgebase-specific utility is used and avoids divergence.

In
@backend/plugins/frontline_api/src/modules/knowledgebase/db/definitions/topic.ts:
- Line 2: The generic Mongoose helpers field and schemaWrapper should be moved
out of the call module into a shared common DB utilities module; create a new
shared module that exports field and schemaWrapper, update this file (topic.ts)
to import field and schemaWrapper from the new shared utilities module instead
of '~/modules/integrations/call/db/utils', and update other modules (inbox,
integrations/call, etc.) to import from the same shared module; ensure the
original module no longer re-exports these helpers and run/adjust imports and
tests to confirm everything compiles.

In
@backend/plugins/frontline_api/src/modules/knowledgebase/db/models/Article.ts:
- Around line 22-23: The interface method removeDoc currently declares a void
return but the implementation returns a Promise (models.Article.deleteOne({ _id
})); update the contract to match the implementation by changing removeDoc(_id:
string) to return a Promise (e.g., Promise<DeleteResult> or Promise<any>) or
alternatively change the implementation in the Article model to await the delete
and not return a value; ensure the signature and the implementation of removeDoc
are consistent (reference removeDoc and models.Article.deleteOne).
- Around line 92-95: The findOneAndUpdate call on models.Article currently
returns the pre-update document; update the call to include the options object
with { new: true } so it returns the updated document (e.g.,
models.Article.findOneAndUpdate({ _id }, { $set: doc }, { new: true }));
optionally include runValidators: true if you want schema validation on updates.

In
@backend/plugins/frontline_api/src/modules/knowledgebase/db/models/Category.ts:
- Around line 72-74: The error thrown in Category.ts uses inconsistent
terminology ("tag") while the surrounding code deals with categories; update the
thrown Error in the block that checks childrenCounts (the if (childrenCounts >
0) branch) to use "category" (e.g., "Cannot change category: this is a parent
category") or another clear, consistent message mentioning "category" instead of
"tag" so logs and UX match the model semantics.
- Around line 93-105: In removeDoc, the code incorrectly calls
models.Category.deleteMany({ categoryId: _id }); change this to delete child
categories by using parentCategoryId (models.Category.deleteMany({
parentCategoryId: _id })) and also delete associated articles (e.g.,
models.Article.deleteMany({ categoryId: _id })) before calling
models.Category.deleteOne({ _id }); if you need to cascade deeper, implement a
recursive deletion that finds child categories via parentCategoryId and deletes
their articles and children as well; keep all operations awaited and handle
not-found/error cases as currently done in removeDoc.

In @backend/plugins/frontline_api/src/modules/knowledgebase/db/models/Topic.ts:
- Around line 74-80: The cascade delete in Topic.ts is querying and deleting
against the wrong model: replace the use of models.Topic when handling
categories with models.Category so the lookup and removal target categories;
specifically update the block that currently calls models.Topic.find({ topicId:
_id }) and models.Topic.removeDoc(category._id) to call models.Category.find({
topicId: _id }) and models.Category.removeDoc(category._id) so associated
categories are actually deleted.
- Line 16: The interface declares removeDoc(_id: string): void but the
implementation returns the Promise from deleteOne(); update the removeDoc
signature to return a Promise type matching deleteOne's result (e.g.,
Promise<DeleteResult> or at minimum Promise<any>) so the interface and
implementation match; adjust any imports/types if needed and ensure the
removeDoc declaration in Topic (removeDoc) aligns with the deleteOne return
value.

In @backend/plugins/frontline_api/src/modules/knowledgebase/db/utils.ts:
- Around line 3-16: The field function is missing TypeScript types; update the
signature of field to accept a properly typed options parameter (e.g., an
interface/type that includes pkey: boolean, type: any/Constructor like
StringConstructor, optional?: boolean, validate?: RegExp, default?: ()=>string,
etc.) and annotate the return type to be that same options type (or a more
specific schema/options type). Ensure usage sites (pkey, type, optional,
default) and the nanoid assignment are compatible with the chosen types and
export the types if needed so callers can reuse them.
- Around line 18-22: The schemaWrapper function is missing TypeScript types;
update its signature to accept a typed Mongoose Schema and return a Schema with
the added scopeBrandIds field (string[]). Specifically, import the appropriate
mongoose types and change schemaWrapper to a typed generic (e.g., Schema<T>)
parameter and a return type that augments T with { scopeBrandIds: string[] } so
callers and TS can validate the added field.

In
@backend/plugins/frontline_api/src/modules/knowledgebase/graphql/resolvers/customResolvers/article.ts:
- Around line 9-14: The createdUser resolver currently returns a User reference
without checking article.createdBy; update the createdUser(article:
IArticleDocument, _args) resolver to mirror publishedUser by returning null when
article.createdBy is falsy and otherwise return { __typename: 'User', _id:
article.createdBy } so you never return a User with an undefined _id.

In
@backend/plugins/frontline_api/src/modules/knowledgebase/graphql/resolvers/customResolvers/category.ts:
- Around line 40-42: The firstTopic resolver is querying the wrong model —
change the query from models.Category.findOne({ _id: category.topicId }) to use
the Topic model (e.g., models.Topic.findOne({ _id: category.topicId }) or
models.Topic.findById(category.topicId)) inside the async firstTopic(category,
_args, { models }: IContext) function so it returns the topic document instead
of a category.
- Around line 23-38: The authors resolver is querying the wrong model — replace
the call to models.Category.find inside the authors function with
models.Article.find so you fetch articles (not categories) to derive author IDs;
keep the same filter on categoryId and status and the projection { createdBy: 1
}, map the resulting article.createdBy values to the User objects as before.
- Around line 6-21: The articles resolver is querying the wrong model: in the
async articles(category, args, { models }) function replace the call to
models.Category.find(...) with models.Article.find(...) so it returns Article
documents for categoryId = category._id (keeping the existing query
construction, status handling, and .sort({ createdDate: -1 }) behavior); ensure
you only change the model reference (models.Category.find ->
models.Article.find) and leave the query and sorting intact.
- Around line 44-62: The numOfArticles resolver is querying the wrong model
(models.Category) — change it to query the Article model instead; update the
query call in async numOfArticles(...) from
models.Category.find(query).countDocuments() to use models.Article (e.g.,
models.Article.find(query).countDocuments() or
models.Article.countDocuments(query)) so it counts articles in the category,
leaving the existing query logic (category._id, status handling,
PUBLISH_STATUSES) intact and ensuring models.Article is available in the
context.

In
@backend/plugins/frontline_api/src/modules/knowledgebase/graphql/resolvers/customResolvers/topic.ts:
- Around line 19-23: The categories resolver is querying the wrong model: inside
async categories(topic: ITopicDocument, _args, { models }: IContext) it calls
models.Topic.find(...) but should return Category documents; change the query to
use models.Category.find({ topicId: topic._id }).sort({ title: 1 }) (or the
project's Category equivalent) so the resolver returns [KnowledgeBaseCategory]
as the schema expects.
- Around line 25-36: The parentCategories resolver (function parentCategories)
is querying the wrong Mongoose model (models.Topic) but should fetch parent
categories; change the query to use models.Category and keep the same filter on
topicId: topic._id and parentCategoryId being null/absent/empty, then sort by
title to return the expected [KnowledgeBaseParentCategory]; update any
import/typing if necessary so the resolver returns Category documents rather
than Topic documents.

In
@backend/plugins/frontline_api/src/modules/knowledgebase/graphql/resolvers/queries/knowledgeBaseQueries.ts:
- Around line 76-79: The bug is that buildQuery constructs a filter using
topicId (singular) but the code deletes selector.topicIds (plural), leaving the
stale topicId filter; update the deletion to remove selector.topicId instead of
selector.topicIds in the buildQuery logic inside knowledgeBaseQueries (where
selector.categoryId is set) so the temporary topic filter is properly cleared
and the query behaves correctly.

In
@backend/plugins/frontline_api/src/modules/knowledgebase/graphql/schemas/knowledgeBaseTypeDefs.ts:
- Line 97: Rename the GraphQL field 'childrens' to the correct plural 'children'
on the KnowledgeBaseCategory type: update the schema definition
(KnowledgeBaseCategory -> childrens -> children) and then update all references
across resolvers, input/output TypeScript types, fragment/query usages, and any
DB mapping or population code that expects 'childrens' to use 'children' so
field names remain consistent throughout the codebase.
🧹 Nitpick comments (27)
backend/plugins/frontline_api/src/modules/knowledgebase/utils/constants.ts (1)

1-5: Consider adding as const for stricter type safety.

Adding as const preserves literal types instead of widening to string, which improves type inference when these values are used elsewhere (e.g., in discriminated unions or type guards). Also, the indentation is inconsistent (4 spaces for properties vs 2 spaces for closing brace).

♻️ Suggested improvement
-export const MODULE_NAMES = {
-    KB_TOPIC: 'knowledgeBaseTopic',
-    KB_CATEGORY: 'knowledgeBaseCategory',
-    KB_ARTICLE: 'knowledgeBaseArticle',
-  };
+export const MODULE_NAMES = {
+  KB_TOPIC: 'knowledgeBaseTopic',
+  KB_CATEGORY: 'knowledgeBaseCategory',
+  KB_ARTICLE: 'knowledgeBaseArticle',
+} as const;
backend/plugins/frontline_api/src/modules/knowledgebase/@types/category.ts (1)

5-12: Consider making title required.

All fields in ICategory are optional, which may allow creating categories without essential data. Typically, title would be a required field for a category entity.

Suggested change
 export interface ICategory {
-    title?: string;
+    title: string;
     description?: string;
     articleIds?: string[];
     icon?: string;
     parentCategoryId?: string;
     topicId?: string;
   }
backend/plugins/frontline_api/src/modules/knowledgebase/@types/topic.ts (1)

4-14: Duplicate code field and consider making title required.

  1. The code field is already defined in ICommonFields (which ITopicDocument extends), creating redundancy.
  2. Similar to ICategory, consider whether title should be required.
Suggested change
 export interface ITopic {
-    title?: string;
-    code?: string;
+    title: string;
     description?: string;
     brandId?: string;
     categoryIds?: string[];
     color?: string;
     backgroundImage?: string;
     languageCode?: string;
     notificationSegmentId?: string;
   }
backend/plugins/frontline_api/src/apollo/typeDefs.ts (1)

18-19: Minor: Trailing blank lines added.

These trailing blank lines don't affect functionality. Consider removing if not required by formatting rules.

backend/plugins/frontline_api/src/apollo/schema/schema.ts (1)

88-92: Missing semicolon at end of import statement.

The import statement is missing a trailing semicolon, which is inconsistent with other imports in this file.

🔧 Suggested fix
 import {
   queries as KnowledgeBaseQueries,
   mutations as KnowledgeBaseMutations,
   types as KnowledgeBaseTypes,
-} from '@/knowledgebase/graphql/schemas/knowledgeBaseTypeDefs'
+} from '@/knowledgebase/graphql/schemas/knowledgeBaseTypeDefs';
backend/plugins/frontline_api/src/apollo/resolvers/mutations.ts (1)

14-14: Missing semicolon at end of import statement.

Inconsistent with other imports in this file.

🔧 Suggested fix
-import { knowledgeBaseMutations } from '@/knowledgebase/graphql/resolvers/mutations/knowledgeBaseMutations'
+import { knowledgeBaseMutations } from '@/knowledgebase/graphql/resolvers/mutations/knowledgeBaseMutations';
backend/plugins/frontline_api/src/apollo/resolvers/queries.ts (1)

16-16: Missing semicolon at end of import statement.

Inconsistent with other imports in this file.

🔧 Suggested fix
-import { knowledgeBaseQueries } from '@/knowledgebase/graphql/resolvers/queries/knowledgeBaseQueries'
+import { knowledgeBaseQueries } from '@/knowledgebase/graphql/resolvers/queries/knowledgeBaseQueries';
backend/plugins/frontline_api/src/modules/knowledgebase/db/definitions/topic.ts (1)

35-36: Minor: Remove unnecessary blank lines.

There are extra blank lines that could be cleaned up for consistency.

🔧 Suggested fix
       notificationSegmentId: field({
         type: String,
         required: false,
       }),
-  
-      
-  
       ...commonFields,
     }),
   );
backend/plugins/frontline_api/src/modules/knowledgebase/db/definitions/article.ts (2)

1-4: Inconsistent import path aliases.

The file mixes ~/ (line 1) and @/ (line 2) path aliases. This inconsistency can cause confusion and maintenance issues. Standardize on one alias pattern.

Proposed fix
 import { field } from '~/modules/knowledgebase/db/utils';
-import { PUBLISH_STATUSES, commonFields } from '@/knowledgebase/db/definitions/constant'
+import { PUBLISH_STATUSES, commonFields } from '~/modules/knowledgebase/db/definitions/constant';
 import { Schema } from 'mongoose';
-import { attachmentSchema } from 'erxes-api-shared/core-modules';
+import { attachmentSchema } from 'erxes-api-shared/core-modules';

51-51: Minor formatting: missing space after colon.

-    publishedUserId:field({ type: String, optional: true, label: 'Published user'}),
+    publishedUserId: field({ type: String, optional: true, label: 'Published user' }),
backend/plugins/frontline_api/src/modules/knowledgebase/graphql/resolvers/customResolvers/article.ts (1)

1-2: Inconsistent import path aliases.

Same issue as other files - mixing @/ and ~/ aliases. Standardize for consistency.

-import { IArticleDocument } from '@/knowledgebase/@types/article';
-import { IContext } from '~/connectionResolvers'
+import { IArticleDocument } from '~/modules/knowledgebase/@types/article';
+import { IContext } from '~/connectionResolvers';
backend/plugins/frontline_api/src/modules/knowledgebase/graphql/resolvers/mutations/knowledgeBaseMutations.ts (3)

35-35: Stray semicolon on empty line.

This appears to be a leftover artifact.

-;

103-109: Consider extracting duplicated scheduled date validation.

The same validation logic for scheduled articles is repeated in both Add and Edit mutations.

Example extraction
function validateScheduledArticle(doc: IArticleCreate): void {
  if (doc.status === 'scheduled' && !doc.scheduledDate) {
    throw new Error('Scheduled Date must be supplied');
  }
  if (doc.status === 'scheduled' && doc.scheduledDate && doc.scheduledDate < new Date()) {
    throw new Error('Scheduled Date can not be in the past!');
  }
}

Then use validateScheduledArticle(doc) in both mutations.

Also applies to: 126-132


28-28: Unused fetch results - clarify intent with comments or remove.

Several mutations fetch entities (e.g., getTopic, getCategory, getArticle) but don't use the result. If this is for existence validation (throwing if not found), consider adding a brief comment to clarify intent, or use a dedicated exists check.

Also applies to: 45-45, 71-71, 86-86, 124-124, 149-149

backend/plugins/frontline_api/src/modules/knowledgebase/db/definitions/constant.ts (1)

12-19: Consider making createdBy and modifiedBy optional to prevent validation errors.

The field utility applies /\S+/ validation to non-optional String fields. While current code enforces userId through createDoc/updateDoc methods, making these fields optional adds defensive protection against bypassing those methods or future use of direct model creation.

backend/plugins/frontline_api/src/modules/knowledgebase/graphql/schemas/knowledgeBaseTypeDefs.ts (3)

35-36: Minor formatting inconsistency: missing spaces before colons.

For consistency with the rest of the schema, add spaces before the colons.

-    publishedUserId:String
-    publishedUser:User
+    publishedUserId: String
+    publishedUser: User

77-77: Minor formatting: missing space before colon.

-      countArticles:Int
+      countArticles: Int

151-156: Inconsistent spacing in query parameters.

For readability and consistency, add spaces after colons in parameter definitions.

-    knowledgeBaseCategories(page: Int, perPage: Int, ids:[String], topicIds: [String], codes: [String],icon:String): [KnowledgeBaseCategory]
+    knowledgeBaseCategories(page: Int, perPage: Int, ids: [String], topicIds: [String], codes: [String], icon: String): [KnowledgeBaseCategory]
...
-    knowledgeBaseArticles(searchValue: String, page: Int, perPage: Int, categoryIds: [String],articleIds:[String], codes: [String], topicIds: [String], sortField:String, sortDirection: Int, status: String): [KnowledgeBaseArticle]
+    knowledgeBaseArticles(searchValue: String, page: Int, perPage: Int, categoryIds: [String], articleIds: [String], codes: [String], topicIds: [String], sortField: String, sortDirection: Int, status: String): [KnowledgeBaseArticle]
backend/plugins/frontline_api/src/modules/knowledgebase/@types/article.ts (2)

5-8: Consider exporting IFormCodes interface.

This interface might be needed by other modules (e.g., for type-checking form code inputs in mutations). If it's only used internally, this is fine, but exporting it would improve reusability.

♻️ Proposed change
-interface IFormCodes {
+export interface IFormCodes {
     brandId: string;
     formId: string;
 }

30-32: Fix indentation for _id field.

The _id field has inconsistent indentation compared to the rest of the codebase.

♻️ Proposed fix
 export interface IArticleDocument extends ICommonFields, IArticle, Document {
-_id: string;
+  _id: string;
 }
backend/plugins/frontline_api/src/modules/knowledgebase/db/models/Topic.ts (2)

31-42: createDoc signature allows optional userId but throws if not provided.

The method signature declares userId as optional (userId?: string), but the implementation immediately throws if it's not supplied. Consider making userId required in the signature to provide better type safety and clearer API expectations.

♻️ Proposed change in interface
-    createDoc(docFields: ITopic, userId?: string): Promise<ITopicDocument>;
+    createDoc(docFields: ITopic, userId: string): Promise<ITopicDocument>;

And in the implementation:

-      public static createDoc(docFields: ITopic, userId?: string) {
-        if (!userId) {
-          throw new Error('userId must be supplied');
-        }
+      public static createDoc(docFields: ITopic, userId: string) {

44-51: Same issue: updateDoc allows optional userId but throws if not provided.

Apply the same fix as createDoc - make userId required in both the interface and implementation.

backend/plugins/frontline_api/src/modules/knowledgebase/db/models/Category.ts (1)

1-2: Consolidate imports from the same module.

♻️ Suggested refactor
-import { ICategoryDocument } from '../../@types/category';
-import { ICategory } from '../../@types/category';
+import { ICategory, ICategoryDocument } from '../../@types/category';
backend/plugins/frontline_api/src/modules/knowledgebase/db/models/Article.ts (2)

74-78: Redundant null check — getArticle already throws if not found.

The getArticle method throws an error when the article is not found, making the subsequent if(!article) check unreachable.

♻️ Proposed fix
       public static async updateDoc(
         _id: string,
         docFields: IArticleCreate,
         userId?: string
       ) {
         if (!userId) {
           throw new Error('userId must be supplied');
         }
         const article = await models.Article.getArticle(_id);
-
-        if(!article){
-          throw new Error('Article not found')
-        }
 
         const doc = {

110-118: Reaction count can go negative if decrementing below zero.

Consider adding a floor check to prevent negative counts.

♻️ Proposed fix
         const reactionCounts = article.reactionCounts || {};
 
-        reactionCounts[reactionChoice] =
-          (reactionCounts[reactionChoice] || 0) + (modifyType === 'inc' ? 1 : -1);
+        const currentCount = reactionCounts[reactionChoice] || 0;
+        reactionCounts[reactionChoice] = Math.max(0, currentCount + (modifyType === 'inc' ? 1 : -1));
 
         await models.Article.updateOne(
backend/plugins/frontline_api/src/modules/knowledgebase/graphql/resolvers/queries/knowledgeBaseQueries.ts (2)

14-18: Fragile string manipulation for field name mapping.

key.replace('s', '') relies on the assumption that removing the first 's' produces the correct field name. This works for the current keys but is unclear and error-prone for future additions.

♻️ Proposed fix — use explicit mapping
-const buildQuery = (args: any) => {
+const buildQuery = (args: any) => {
   const qry: any = {};
 
-  const keys = ['codes', 'categoryIds', 'articleIds', 'topicIds'];
+  const keyToField: Record<string, string> = {
+    codes: 'code',
+    categoryIds: 'categoryId',
+    articleIds: 'articleId',
+    topicIds: 'topicId',
+  };
 
-  keys.forEach((key) => {
+  Object.entries(keyToField).forEach(([key, field]) => {
     if (args[key] && args[key].length > 0) {
-      const field = key.replace('s', '');
       qry[field] = { $in: args[key] };
     }
   });

21-27: Unescaped regex input may cause unexpected matches or ReDoS.

User-supplied searchValue is interpolated directly into a regex pattern. Special regex characters (e.g., ., *, +) will be interpreted as regex operators rather than literals.

♻️ Proposed fix — escape special characters
+const escapeRegex = (str: string) => str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
+
 const buildQuery = (args: any) => {
   // ...
   if (args.searchValue && args.searchValue.trim()) {
+    const escaped = escapeRegex(args.searchValue.trim());
     qry.$or = [
-      { title: { $regex: `.*${args.searchValue.trim()}.*`, $options: 'i' } },
-      { content: { $regex: `.*${args.searchValue.trim()}.*`, $options: 'i' } },
-      { summary: { $regex: `.*${args.searchValue.trim()}.*`, $options: 'i' } },
+      { title: { $regex: escaped, $options: 'i' } },
+      { content: { $regex: escaped, $options: 'i' } },
+      { summary: { $regex: escaped, $options: 'i' } },
     ];
   }

Note: The .* wrappers are also unnecessary since regex already matches substrings by default.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 77ce65e and 17670ab.

📒 Files selected for processing (25)
  • backend/plugins/frontline_api/src/apollo/resolvers/mutations.ts
  • backend/plugins/frontline_api/src/apollo/resolvers/queries.ts
  • backend/plugins/frontline_api/src/apollo/resolvers/resolvers.ts
  • backend/plugins/frontline_api/src/apollo/schema/schema.ts
  • backend/plugins/frontline_api/src/apollo/typeDefs.ts
  • backend/plugins/frontline_api/src/connectionResolvers.ts
  • backend/plugins/frontline_api/src/modules/knowledgebase/@types/article.ts
  • backend/plugins/frontline_api/src/modules/knowledgebase/@types/category.ts
  • backend/plugins/frontline_api/src/modules/knowledgebase/@types/common.ts
  • backend/plugins/frontline_api/src/modules/knowledgebase/@types/topic.ts
  • backend/plugins/frontline_api/src/modules/knowledgebase/db/definitions/article.ts
  • backend/plugins/frontline_api/src/modules/knowledgebase/db/definitions/category.ts
  • backend/plugins/frontline_api/src/modules/knowledgebase/db/definitions/constant.ts
  • backend/plugins/frontline_api/src/modules/knowledgebase/db/definitions/topic.ts
  • backend/plugins/frontline_api/src/modules/knowledgebase/db/models/Article.ts
  • backend/plugins/frontline_api/src/modules/knowledgebase/db/models/Category.ts
  • backend/plugins/frontline_api/src/modules/knowledgebase/db/models/Topic.ts
  • backend/plugins/frontline_api/src/modules/knowledgebase/db/utils.ts
  • backend/plugins/frontline_api/src/modules/knowledgebase/graphql/resolvers/customResolvers/article.ts
  • backend/plugins/frontline_api/src/modules/knowledgebase/graphql/resolvers/customResolvers/category.ts
  • backend/plugins/frontline_api/src/modules/knowledgebase/graphql/resolvers/customResolvers/topic.ts
  • backend/plugins/frontline_api/src/modules/knowledgebase/graphql/resolvers/mutations/knowledgeBaseMutations.ts
  • backend/plugins/frontline_api/src/modules/knowledgebase/graphql/resolvers/queries/knowledgeBaseQueries.ts
  • backend/plugins/frontline_api/src/modules/knowledgebase/graphql/schemas/knowledgeBaseTypeDefs.ts
  • backend/plugins/frontline_api/src/modules/knowledgebase/utils/constants.ts
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursorrules)

**/*.{ts,tsx}: Write concise, technical TypeScript code with accurate examples
Use functional and declarative programming patterns; avoid classes
Prefer iteration and modularization over code duplication
Use descriptive variable names with auxiliary verbs (e.g., isLoading, hasError)
Structure files: exported component, utils, contexts, hooks, types
Avoid console logs
Always use absolute paths when importing
Favor named exports for components
Use TypeScript for all code; prefer interfaces over types
Avoid enums; use maps instead
Use functional components with TypeScript interfaces
Use the 'function' keyword for pure functions
Avoid unnecessary curly braces in conditionals; use concise syntax for simple statements

Files:

  • backend/plugins/frontline_api/src/modules/knowledgebase/utils/constants.ts
  • backend/plugins/frontline_api/src/modules/knowledgebase/db/definitions/category.ts
  • backend/plugins/frontline_api/src/apollo/typeDefs.ts
  • backend/plugins/frontline_api/src/modules/knowledgebase/db/definitions/topic.ts
  • backend/plugins/frontline_api/src/modules/knowledgebase/db/definitions/article.ts
  • backend/plugins/frontline_api/src/modules/knowledgebase/@types/common.ts
  • backend/plugins/frontline_api/src/apollo/resolvers/mutations.ts
  • backend/plugins/frontline_api/src/modules/knowledgebase/graphql/resolvers/customResolvers/topic.ts
  • backend/plugins/frontline_api/src/modules/knowledgebase/@types/category.ts
  • backend/plugins/frontline_api/src/apollo/resolvers/queries.ts
  • backend/plugins/frontline_api/src/modules/knowledgebase/graphql/resolvers/customResolvers/category.ts
  • backend/plugins/frontline_api/src/modules/knowledgebase/graphql/schemas/knowledgeBaseTypeDefs.ts
  • backend/plugins/frontline_api/src/modules/knowledgebase/@types/article.ts
  • backend/plugins/frontline_api/src/modules/knowledgebase/db/utils.ts
  • backend/plugins/frontline_api/src/modules/knowledgebase/db/models/Article.ts
  • backend/plugins/frontline_api/src/modules/knowledgebase/@types/topic.ts
  • backend/plugins/frontline_api/src/apollo/resolvers/resolvers.ts
  • backend/plugins/frontline_api/src/modules/knowledgebase/graphql/resolvers/mutations/knowledgeBaseMutations.ts
  • backend/plugins/frontline_api/src/modules/knowledgebase/db/models/Category.ts
  • backend/plugins/frontline_api/src/apollo/schema/schema.ts
  • backend/plugins/frontline_api/src/modules/knowledgebase/graphql/resolvers/customResolvers/article.ts
  • backend/plugins/frontline_api/src/modules/knowledgebase/db/models/Topic.ts
  • backend/plugins/frontline_api/src/modules/knowledgebase/db/definitions/constant.ts
  • backend/plugins/frontline_api/src/connectionResolvers.ts
  • backend/plugins/frontline_api/src/modules/knowledgebase/graphql/resolvers/queries/knowledgeBaseQueries.ts
🧬 Code graph analysis (14)
backend/plugins/frontline_api/src/modules/knowledgebase/db/definitions/category.ts (2)
backend/plugins/frontline_api/src/modules/knowledgebase/db/utils.ts (1)
  • field (3-16)
backend/plugins/frontline_api/src/modules/knowledgebase/db/definitions/constant.ts (1)
  • commonFields (12-19)
backend/plugins/frontline_api/src/modules/knowledgebase/db/definitions/article.ts (2)
backend/plugins/frontline_api/src/modules/knowledgebase/db/utils.ts (1)
  • field (3-16)
backend/plugins/frontline_api/src/modules/knowledgebase/db/definitions/constant.ts (2)
  • PUBLISH_STATUSES (5-10)
  • commonFields (12-19)
backend/plugins/frontline_api/src/apollo/resolvers/mutations.ts (1)
backend/plugins/frontline_api/src/modules/knowledgebase/graphql/resolvers/mutations/knowledgeBaseMutations.ts (1)
  • knowledgeBaseMutations (8-163)
backend/plugins/frontline_api/src/modules/knowledgebase/graphql/resolvers/customResolvers/topic.ts (2)
backend/plugins/frontline_api/src/connectionResolvers.ts (1)
  • IContext (237-241)
backend/plugins/frontline_api/src/modules/knowledgebase/@types/topic.ts (1)
  • ITopicDocument (16-18)
backend/plugins/frontline_api/src/modules/knowledgebase/@types/category.ts (2)
backend/plugins/frontline_api/src/modules/knowledgebase/@types/common.ts (1)
  • ICommonFields (1-7)
frontend/libs/ui-modules/src/modules/documents/components/DocumentsInline.tsx (1)
  • Document (14-17)
backend/plugins/frontline_api/src/apollo/resolvers/queries.ts (1)
backend/plugins/frontline_api/src/modules/knowledgebase/graphql/resolvers/queries/knowledgeBaseQueries.ts (1)
  • knowledgeBaseQueries (48-205)
backend/plugins/frontline_api/src/modules/knowledgebase/graphql/resolvers/customResolvers/category.ts (2)
backend/plugins/frontline_api/src/modules/knowledgebase/@types/category.ts (1)
  • ICategoryDocument (14-16)
backend/plugins/frontline_api/src/modules/knowledgebase/db/definitions/constant.ts (1)
  • PUBLISH_STATUSES (5-10)
backend/plugins/frontline_api/src/modules/knowledgebase/graphql/schemas/knowledgeBaseTypeDefs.ts (3)
backend/plugins/frontline_api/src/apollo/schema/schema.ts (3)
  • types (94-111)
  • queries (112-129)
  • mutations (131-146)
backend/plugins/frontline_api/src/apollo/resolvers/queries.ts (1)
  • queries (18-35)
backend/plugins/frontline_api/src/apollo/resolvers/mutations.ts (1)
  • mutations (16-31)
backend/plugins/frontline_api/src/modules/knowledgebase/@types/article.ts (3)
backend/erxes-api-shared/src/core-types/common.ts (1)
  • IPdfAttachment (81-84)
backend/plugins/frontline_api/src/modules/knowledgebase/@types/common.ts (1)
  • ICommonFields (1-7)
frontend/libs/ui-modules/src/modules/documents/components/DocumentsInline.tsx (1)
  • Document (14-17)
backend/plugins/frontline_api/src/modules/knowledgebase/db/models/Article.ts (5)
backend/plugins/frontline_api/src/modules/knowledgebase/@types/article.ts (2)
  • IArticle (10-28)
  • IArticleDocument (30-32)
backend/plugins/content_api/src/modules/cms/graphql/customeResolvers/fieldGroup.ts (1)
  • fields (5-20)
backend/plugins/frontline_api/src/connectionResolvers.ts (1)
  • IModels (180-235)
backend/plugins/frontline_api/src/modules/knowledgebase/db/definitions/constant.ts (1)
  • PUBLISH_STATUSES (5-10)
backend/plugins/frontline_api/src/modules/knowledgebase/db/definitions/article.ts (1)
  • articleSchema (15-57)
backend/plugins/frontline_api/src/modules/knowledgebase/@types/topic.ts (1)
backend/plugins/frontline_api/src/modules/knowledgebase/@types/common.ts (1)
  • ICommonFields (1-7)
backend/plugins/frontline_api/src/modules/knowledgebase/graphql/resolvers/customResolvers/article.ts (2)
backend/plugins/frontline_api/src/connectionResolvers.ts (1)
  • IContext (237-241)
backend/plugins/frontline_api/src/modules/knowledgebase/@types/article.ts (1)
  • IArticleDocument (30-32)
backend/plugins/frontline_api/src/modules/knowledgebase/db/models/Topic.ts (3)
backend/plugins/frontline_api/src/modules/knowledgebase/@types/topic.ts (2)
  • ITopicDocument (16-18)
  • ITopic (4-14)
backend/plugins/frontline_api/src/connectionResolvers.ts (1)
  • IModels (180-235)
backend/plugins/frontline_api/src/modules/knowledgebase/db/definitions/topic.ts (1)
  • topicSchema (5-39)
backend/plugins/frontline_api/src/modules/knowledgebase/db/definitions/constant.ts (1)
backend/plugins/frontline_api/src/modules/knowledgebase/db/utils.ts (1)
  • field (3-16)
🔇 Additional comments (21)
backend/plugins/frontline_api/src/modules/knowledgebase/@types/common.ts (1)

1-7: LGTM!

The interface correctly defines common metadata fields. Minor formatting inconsistency with the closing brace indentation, but this is a nitpick.

backend/plugins/frontline_api/src/modules/knowledgebase/@types/category.ts (1)

14-16: LGTM!

Good use of interface composition for the document type.

backend/plugins/frontline_api/src/modules/knowledgebase/@types/topic.ts (1)

16-18: LGTM!

Proper Mongoose document interface composition.

backend/plugins/frontline_api/src/apollo/schema/schema.ts (1)

110-110: LGTM!

The KnowledgeBase types, queries, and mutations are correctly integrated into the schema assembly, following the established pattern used by other modules in this file.

Also applies to: 128-128, 145-145

backend/plugins/frontline_api/src/apollo/resolvers/mutations.ts (1)

30-30: LGTM!

The knowledgeBaseMutations are correctly spread into the mutations object, following the established pattern.

backend/plugins/frontline_api/src/apollo/resolvers/queries.ts (1)

34-34: LGTM!

The knowledgeBaseQueries are correctly spread into the queries object, following the established pattern.

backend/plugins/frontline_api/src/apollo/resolvers/resolvers.ts (2)

7-12: LGTM!

The KnowledgeBase custom resolver imports are correctly structured, following the existing patterns in this file with a mix of default and named imports as appropriate.


21-24: LGTM!

All four KnowledgeBase resolvers (Article, Category, ParentCategory, Topic) are correctly added to the customResolvers export object. This properly exposes the custom field resolvers for the GraphQL schema.

backend/plugins/frontline_api/src/modules/knowledgebase/db/definitions/topic.ts (1)

37-41: code field is properly included in commonFields.

The index on code is valid. The field is defined in constant.ts as part of commonFields with sparse: true and unique: true already set at the field level, making the explicit index definition at line 41 technically redundant. Consider whether the field-level constraint definitions are sufficient or if the separate index is intentional for clarity.

backend/plugins/frontline_api/src/modules/knowledgebase/db/definitions/category.ts (1)

5-17: Schema definition looks good.

The category schema properly defines all required fields with appropriate types and spreads commonFields for shared metadata.

backend/plugins/frontline_api/src/modules/knowledgebase/db/definitions/article.ts (1)

15-57: Article schema structure is well-defined.

The schema appropriately handles article content, scheduling, reactions, attachments, and relationships to topics/categories.

backend/plugins/frontline_api/src/modules/knowledgebase/graphql/resolvers/customResolvers/article.ts (1)

5-7: LGTM on __resolveReference implementation.

Correctly fetches the article document by _id for federation reference resolution.

backend/plugins/frontline_api/src/modules/knowledgebase/graphql/resolvers/mutations/knowledgeBaseMutations.ts (2)

88-91: Good handling of orphaned child categories.

Correctly unsets parentCategoryId on child categories when a parent is removed, preventing orphaned references.


165-169: Reconsider skipPermission: true for knowledge base mutations — these are administrative operations.

While skipPermission: true is a common pattern in the codebase (used in auth, user registration, and widget endpoints), knowledge base mutations (adding/editing/removing topics, categories, and articles) are administrative operations that typically require authorization. Confirm this is intentional and not inappropriately copied from other modules.

backend/plugins/frontline_api/src/modules/knowledgebase/db/definitions/constant.ts (2)

5-10: LGTM on PUBLISH_STATUSES definition.

Using an object with string values follows the coding guidelines preference for maps over enums.


1-1: Verify import path alias consistency.

This file uses ~/modules/... which is good. Ensure other files in this module use the same pattern.

backend/plugins/frontline_api/src/modules/knowledgebase/graphql/resolvers/customResolvers/topic.ts (1)

4-7: LGTM!

The __resolveReference implementation correctly fetches a topic by _id for Apollo Federation.

backend/plugins/frontline_api/src/connectionResolvers.ts (3)

172-178: LGTM!

The imports follow the established pattern using absolute paths with the @ alias, consistent with other knowledgebase module imports.


229-234: LGTM!

The IModels interface additions follow the established pattern for other domain models.


412-426: LGTM!

The model registrations follow the established pattern with consistent collection naming (knowledgebase_*) and proper type parameters.

backend/plugins/frontline_api/src/modules/knowledgebase/graphql/resolvers/queries/knowledgeBaseQueries.ts (1)

5-7: LGTM!

The findDetail helper correctly supports lookup by both _id and code fields using $or.

@@ -0,0 +1,19 @@
import { Schema } from 'mongoose';
import { field } from '~/modules/integrations/call/db/utils';
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Incorrect import path for field utility.

The import uses ~/modules/integrations/call/db/utils but this file belongs to the knowledgebase module, which has its own field utility at ~/modules/knowledgebase/db/utils. This inconsistency could lead to maintenance issues and unexpected behavior if the utilities diverge.

Proposed fix
-import { field } from '~/modules/integrations/call/db/utils';
+import { field } from '~/modules/knowledgebase/db/utils';
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import { field } from '~/modules/integrations/call/db/utils';
import { field } from '~/modules/knowledgebase/db/utils';
🤖 Prompt for AI Agents
In
@backend/plugins/frontline_api/src/modules/knowledgebase/db/definitions/category.ts
at line 2, The file imports the shared utility 'field' from the
integrations/call module instead of the knowledgebase module; update the import
in category.ts to use the knowledgebase module's db utils implementation of
'field' (replace the current integrations/call import with the knowledgebase
db/utils import) so the knowledgebase-specific utility is used and avoids
divergence.

@@ -0,0 +1,41 @@
import { Schema } from 'mongoose';
import { field, schemaWrapper } from '~/modules/integrations/call/db/utils';
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -e

# Check for knowledgebase-specific utils
echo "=== Checking for knowledgebase-specific utils ==="
fd -t f "utils.ts" --full-path "knowledgebase" 2>/dev/null || echo "No knowledgebase-specific utils found"

echo -e "\n=== Checking call/db/utils content and location ==="
find . -path "*modules/integrations/call/db/utils.ts" -type f 2>/dev/null | head -5

echo -e "\n=== Checking if call/db/utils.ts exists and its exports ==="
if [ -f "backend/plugins/frontline_api/src/modules/integrations/call/db/utils.ts" ]; then
  echo "--- call/db/utils.ts exports ---"
  head -30 "backend/plugins/frontline_api/src/modules/integrations/call/db/utils.ts"
fi

echo -e "\n=== Checking how many files import from call/db/utils ==="
rg "from.*integrations/call/db/utils" --type ts -c 2>/dev/null | head -20

echo -e "\n=== Files importing from call/db/utils ==="
rg "from.*integrations/call/db/utils" --type ts -l 2>/dev/null

echo -e "\n=== Checking the actual topic.ts file ==="
if [ -f "backend/plugins/frontline_api/src/modules/knowledgebase/db/definitions/topic.ts" ]; then
  echo "--- topic.ts content ---"
  head -50 "backend/plugins/frontline_api/src/modules/knowledgebase/db/definitions/topic.ts"
fi

Repository: erxes/erxes

Length of output: 2644


Move schema utilities to a shared location.

The field and schemaWrapper utilities are generic Mongoose schema helpers, not specific to the call module. They are currently used by at least three unrelated modules (knowledgebase, inbox, and integrations/call itself), creating unnecessary cross-module coupling. Move these utilities to a shared/common schema utilities location (e.g., src/modules/common/db/utils.ts or similar) to clarify dependencies and improve module organization.

🤖 Prompt for AI Agents
In
@backend/plugins/frontline_api/src/modules/knowledgebase/db/definitions/topic.ts
at line 2, The generic Mongoose helpers field and schemaWrapper should be moved
out of the call module into a shared common DB utilities module; create a new
shared module that exports field and schemaWrapper, update this file (topic.ts)
to import field and schemaWrapper from the new shared utilities module instead
of '~/modules/integrations/call/db/utils', and update other modules (inbox,
integrations/call, etc.) to import from the same shared module; ensure the
original module no longer re-exports these helpers and run/adjust imports and
tests to confirm everything compiles.

Comment on lines +22 to +23
): Promise<IArticleDocument>;
removeDoc(_id: string): void;
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Interface mismatch: removeDoc return type is void but implementation returns a Promise.

The interface declares removeDoc(_id: string): void but the implementation returns models.Article.deleteOne({ _id }) which is a Promise.

✏️ Proposed fix
-    removeDoc(_id: string): void;
+    removeDoc(_id: string): Promise<any>;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
): Promise<IArticleDocument>;
removeDoc(_id: string): void;
): Promise<IArticleDocument>;
removeDoc(_id: string): Promise<any>;
🤖 Prompt for AI Agents
In @backend/plugins/frontline_api/src/modules/knowledgebase/db/models/Article.ts
around lines 22 - 23, The interface method removeDoc currently declares a void
return but the implementation returns a Promise (models.Article.deleteOne({ _id
})); update the contract to match the implementation by changing removeDoc(_id:
string) to return a Promise (e.g., Promise<DeleteResult> or Promise<any>) or
alternatively change the implementation in the Article model to await the delete
and not return a value; ensure the signature and the implementation of removeDoc
are consistent (reference removeDoc and models.Article.deleteOne).

Comment on lines +92 to +95
return await models.Article.findOneAndUpdate(
{ _id },
{$set: doc}
);
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Bug: findOneAndUpdate without { new: true } returns stale data.

The method returns the document before the update. To return the updated document, add { new: true }.

🐛 Proposed fix
         return await models.Article.findOneAndUpdate(
           { _id },
-          {$set: doc}
+          { $set: doc },
+          { new: true }
         );
🤖 Prompt for AI Agents
In @backend/plugins/frontline_api/src/modules/knowledgebase/db/models/Article.ts
around lines 92 - 95, The findOneAndUpdate call on models.Article currently
returns the pre-update document; update the call to include the options object
with { new: true } so it returns the updated document (e.g.,
models.Article.findOneAndUpdate({ _id }, { $set: doc }, { new: true }));
optionally include runValidators: true if you want schema validation on updates.

Comment on lines +72 to +74
if (childrenCounts > 0) {
throw new Error('Cannot change category. this is parent tag');
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Inconsistent terminology: error message says "tag" but context is "category".

✏️ Proposed fix
           if (childrenCounts > 0) {
-            throw new Error('Cannot change category. this is parent tag');
+            throw new Error('Cannot change category. This category has children');
           }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (childrenCounts > 0) {
throw new Error('Cannot change category. this is parent tag');
}
if (childrenCounts > 0) {
throw new Error('Cannot change category. This category has children');
}
🤖 Prompt for AI Agents
In
@backend/plugins/frontline_api/src/modules/knowledgebase/db/models/Category.ts
around lines 72 - 74, The error thrown in Category.ts uses inconsistent
terminology ("tag") while the surrounding code deals with categories; update the
thrown Error in the block that checks childrenCounts (the if (childrenCounts >
0) branch) to use "category" (e.g., "Cannot change category: this is a parent
category") or another clear, consistent message mentioning "category" instead of
"tag" so logs and UX match the model semantics.

authors: [User]
numOfArticles(status: String): Float

childrens: [KnowledgeBaseCategory]
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Grammatical error: childrens should be children.

"Children" is already the plural form of "child".

-      childrens: [KnowledgeBaseCategory]
+      children: [KnowledgeBaseCategory]
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
childrens: [KnowledgeBaseCategory]
children: [KnowledgeBaseCategory]
🤖 Prompt for AI Agents
In
@backend/plugins/frontline_api/src/modules/knowledgebase/graphql/schemas/knowledgeBaseTypeDefs.ts
at line 97, Rename the GraphQL field 'childrens' to the correct plural
'children' on the KnowledgeBaseCategory type: update the schema definition
(KnowledgeBaseCategory -> childrens -> children) and then update all references
across resolvers, input/output TypeScript types, fragment/query usages, and any
DB mapping or population code that expects 'childrens' to use 'children' so
field names remain consistent throughout the codebase.

Copy link
Contributor

@ellipsis-dev ellipsis-dev bot left a comment

Choose a reason for hiding this comment

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

Caution

Changes requested ❌

Reviewed 5b2d99a in 3 minutes and 0 seconds. Click for details.
  • Reviewed 517 lines of code in 14 files
  • Skipped 0 files when reviewing.
  • Skipped posting 12 draft comments. View those below.
  • Modify your settings and rules to customize what types of comments Ellipsis leaves. And don't forget to react with 👍 or 👎 to teach Ellipsis.
1. backend/plugins/frontline_api/src/modules/integrations/instagram/@types/bots.ts:4
  • Draft comment:
    Consider using a consistent type for '_id': in IPersistentMenus it’s defined as number, but in IBotDocument (via Document) it’s string. Verify if this is intentional.
  • Reason this comment was not posted:
    Decided after close inspection that this draft comment was likely wrong and/or not actionable: usefulness confidence = 10% vs. threshold = 50% The comment identifies a potential inconsistency in type definitions. However, the two _id fields are in completely different contexts: IPersistentMenus._id appears to be an identifier for menu items (possibly just an index or menu item ID), while IBotDocument._id is the MongoDB document ID (from the Document interface). These serve different purposes and it's reasonable for them to have different types. More importantly, the comment ends with "Verify if this is intentional" which is explicitly against the rules - we should not ask the PR author to confirm, verify, or double-check things. The comment is speculative and asks for verification rather than pointing out a definite issue. Could this actually be a legitimate bug where the developer accidentally used number instead of string for the persistent menu ID? MongoDB typically uses string IDs, so maybe this is worth flagging even if it requires verification. While it could be a bug, the two _id fields serve completely different purposes in different contexts. IPersistentMenus is not a MongoDB document - it's just a plain interface for menu items, so using number as an ID is perfectly reasonable. The comment explicitly asks to "Verify if this is intentional" which violates the rules. Without strong evidence this is wrong, and given the speculative nature, this should be deleted. Delete this comment. It asks the PR author to verify/confirm their intention, which violates the rules. The two _id fields are in different contexts (menu items vs MongoDB documents) and there's no strong evidence that using different types is incorrect.
2. backend/plugins/frontline_api/src/modules/integrations/instagram/@types/bots.ts:26
  • Draft comment:
    Add a trailing newline at the end of the file for consistency.
  • Reason this comment was not posted:
    Comment looked like it was already resolved.
3. backend/plugins/frontline_api/src/modules/integrations/instagram/@types/utils.ts:6
  • Draft comment:
    Add an explicit type annotation for the 'options' parameter in the 'field' function to improve type safety.
  • Reason this comment was not posted:
    Decided after close inspection that this draft comment was likely wrong and/or not actionable: usefulness confidence = 20% vs. threshold = 50% This comment is suggesting a type safety improvement. However, I need to consider: 1) Is this obvious or unimportant? Adding Record<string, any> doesn't actually improve type safety much since any still allows anything. 2) The rules state not to comment on things that are obvious or unimportant. 3) The comment is technically about code quality/refactoring, which can be good if actionable and clear. However, Record<string, any> is barely better than implicit any - it's more of a stylistic preference than a meaningful improvement. 4) This seems like a minor code style suggestion rather than a clear code quality issue. 5) The suggestion doesn't provide strong type safety since it still uses any. The comment could be considered actionable since it provides a specific code suggestion. Also, making implicit types explicit could be seen as a legitimate code quality improvement, even if the type is still any. Perhaps this is a reasonable suggestion for consistency with TypeScript best practices. While making types explicit can be good practice, the suggested type Record<string, any> provides minimal actual type safety improvement over implicit any. This feels more like a minor stylistic preference rather than a clear, important code quality issue. The rules emphasize not making obvious or unimportant comments, and this falls into that category. This comment should be deleted. While it's technically about type safety, the suggested change from implicit any to explicit Record<string, any> provides minimal practical benefit and is more of a minor stylistic preference than an important code quality improvement.
4. backend/plugins/frontline_api/src/modules/knowledgebase/db/definitions/category.ts:8
  • Draft comment:
    Consider adding a default value (e.g., an empty array) for 'articleIds' so that it initializes properly when no articles are provided.
  • Reason this comment was not posted:
    Confidence changes required: 50% <= threshold 50% None
5. backend/plugins/frontline_api/src/modules/knowledgebase/db/definitions/category.ts:24
  • Draft comment:
    Add a trailing newline at the end of the file for consistency.
  • Reason this comment was not posted:
    Comment was on unchanged code.
6. backend/plugins/frontline_api/src/modules/knowledgebase/graphql/resolvers/mutations/knowledgeBaseMutations.ts:35
  • Draft comment:
    Remove the stray semicolon; it appears to be extraneous.
  • Reason this comment was not posted:
    Comment was not on a location in the diff, so it can't be submitted as a review comment.
7. backend/plugins/frontline_api/src/modules/integrations/instagram/@types/conversationMessages.ts:26
  • Draft comment:
    Add a trailing newline at the end of the file for consistency.
  • Reason this comment was not posted:
    Decided after close inspection that this draft comment was likely wrong and/or not actionable: usefulness confidence = 10% vs. threshold = 50% This is a purely stylistic comment about file formatting. While having a trailing newline is a common convention and best practice, this type of issue is typically handled automatically by linters, formatters, or pre-commit hooks. The comment doesn't point out any functional issue or important code quality problem. According to the rules, I should not comment on things that are obvious or unimportant. A missing trailing newline is a very minor issue that would be caught by automated tools. This falls under "obvious or unimportant" comments that should be removed. Some projects do enforce trailing newlines as part of their coding standards, and this could be a legitimate style requirement. The comment is technically correct and actionable - the author can easily add the newline. While the comment is technically correct, it's the type of trivial formatting issue that should be handled by automated tooling rather than manual code review. This is exactly the kind of "obvious or unimportant" comment that the rules say to avoid. If the project cares about this, it should be enforced by a linter. This comment should be deleted. It's about a trivial formatting issue (missing trailing newline) that is too minor and obvious to warrant a manual code review comment. Such issues should be caught by automated linters or formatters.
8. backend/plugins/frontline_api/src/modules/integrations/instagram/@types/postConversations.ts:21
  • Draft comment:
    Add a trailing newline at the end of the file for consistency.
  • Reason this comment was not posted:
    Comment was not on a location in the diff, so it can't be submitted as a review comment.
9. backend/plugins/frontline_api/src/modules/knowledgebase/db/definitions/topic.ts:27
  • Draft comment:
    Add a trailing newline at the end of the file for consistency.
  • Reason this comment was not posted:
    Decided after close inspection that this draft comment was likely wrong and/or not actionable: usefulness confidence = 10% vs. threshold = 50% This is a very minor stylistic comment about file formatting. While having trailing newlines is a common convention and some linters enforce it, this falls into the category of "obvious or unimportant" comments. It's not a functional issue, and if the project cares about this, it would be caught by linters or formatters in the build process. The rules explicitly state "Do NOT make comments that are obvious or unimportant" and "Do NOT comment on anything that would be obviously caught by the build." This is a trivial formatting issue that doesn't affect functionality. Some projects do enforce trailing newlines as part of their coding standards, and this could be a legitimate style requirement. If there's no automated linter catching this, a human comment might be the only way to enforce it. While some projects do enforce this, the rules explicitly state not to make obvious or unimportant comments. A missing trailing newline is extremely minor and doesn't affect code functionality. If it's important to the project, it should be caught by automated tooling, not manual review. This comment should be deleted. It's a trivial formatting issue that falls under "obvious or unimportant" comments. The absence of a trailing newline doesn't affect functionality and should be handled by automated linting tools if it matters to the project.
10. backend/plugins/frontline_api/src/modules/integrations/instagram/@types/comment_conversations_reply.ts:6
  • Draft comment:
    Typo: Inconsistent type usage for 'parentId'. Other fields use the lowercase 'string' primitive type. It should be 'parentId: string;' instead of 'String'.
  • Reason this comment was not posted:
    Marked as duplicate.
11. backend/plugins/frontline_api/src/modules/integrations/instagram/@types/customers.ts:15
  • Draft comment:
    Typo/lexicographical review comment: The file currently does not end with a newline. Please add a newline at the end of the file for consistency.
  • Reason this comment was not posted:
    Decided after close inspection that this draft comment was likely wrong and/or not actionable: usefulness confidence = 10% vs. threshold = 50% This comment is about a very minor formatting issue - missing a newline at the end of a file. While this is technically a valid style convention in many codebases, the rules explicitly state "Do NOT make comments that are obvious or unimportant." A missing newline at EOF is typically caught by linters (like ESLint, Prettier) or pre-commit hooks in modern development workflows. This is an extremely minor issue that doesn't affect functionality and would likely be automatically fixed by the project's formatting tools. The comment doesn't suggest any code logic change or quality improvement - it's purely about formatting. Some projects do enforce newlines at EOF as part of their style guide, and if there's no automated tooling to catch this, a human review comment might be the only way to catch it. The comment is technically correct and actionable. While the comment may be technically correct, it falls under "obvious or unimportant" comments that should not be made. Modern development environments almost universally have linters or formatters that handle this automatically. This is exactly the type of trivial formatting issue that automated tools should catch, not human reviewers. This comment should be deleted. It's about a trivial formatting issue (missing EOF newline) that is unimportant and would typically be caught by automated linting/formatting tools. It doesn't provide meaningful value to the code review.
12. backend/plugins/frontline_api/src/modules/integrations/instagram/@types/postConversations.ts:14
  • Draft comment:
    Typographical note: The type for 'permalink_url' is declared as 'String' with a capital 'S'. Typically in TypeScript, it's preferable to use the primitive type 'string' instead. If this was unintentional, please consider changing it to 'string' for consistency and best practices.
  • Reason this comment was not posted:
    Marked as duplicate.

Workflow ID: wflow_zimmI43ZHwXICyOz

You can customize Ellipsis by changing your verbosity settings, reacting with 👍 or 👎, replying to comments, or adding code review rules.

export interface ICommentConversationReply {
mid: string;
commentConversationId: string;
parentId: String;
Copy link
Contributor

Choose a reason for hiding this comment

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

Use lowercase string instead of String for parentId to adhere to TypeScript best practices.

Suggested change
parentId: String;
parentId: string;

content: string;
integrationId: string;
customerId?: string;
permalink_url: String;
Copy link
Contributor

Choose a reason for hiding this comment

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

Use lowercase string instead of String for permalink_url for consistency.

Suggested change
permalink_url: String;
permalink_url: string;

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

🤖 Fix all issues with AI agents
In
@backend/plugins/frontline_api/src/modules/integrations/instagram/@types/comment_conversations_reply.ts:
- Line 6: The field declaration "parentId: String;" uses the boxed JS type;
change it to the TypeScript primitive "parentId: string;" (matching other string
fields in the same interface) so the interface in comment_conversations_reply.ts
uses consistent primitive string types.

In
@backend/plugins/frontline_api/src/modules/integrations/instagram/@types/postConversations.ts:
- Line 14: The property permalink_url in the type declaration uses the wrapper
type String instead of the primitive string; change permalink_url: String to
permalink_url: string in the postConversations type to match idiomatic
TypeScript and the adjacent string[] usage.

In
@backend/plugins/frontline_api/src/modules/integrations/instagram/@types/utils.ts:
- Around line 6-20: The field function’s options parameter is untyped; add a
TypeScript interface (e.g., FieldOptions) that describes pkey?: boolean, type?:
any (or a tighter constructor type), optional?: boolean, validate?: RegExp |
Function, default?: any, etc., then annotate the function as export const field
= (options: FieldOptions) => { ... } and update any usages; leave the existing
pkey-handling block (the "TODO: remove") in place for now but create/track a
separate issue to remove or refactor it later (do not remove it in this change).

In
@backend/plugins/frontline_api/src/modules/knowledgebase/graphql/resolvers/mutations/knowledgeBaseMutations.ts:
- Around line 23-38: In knowledgeBaseTopicsEdit remove the stray isolated
semicolon after the update call and eliminate unused variables: delete the
unused const topic = await models.Topic.getTopic(_id) (or use its result if
intended), and remove subdomain from the resolver context destructuring if it's
not needed; ensure the function only references models.Topic.updateDoc and
returns updated.
🧹 Nitpick comments (13)
backend/plugins/frontline_api/src/modules/integrations/instagram/@types/conversationMessages.ts (1)

10-10: Consider replacing any with more specific types.

Using any for attachments and botData reduces type safety. Consider defining proper interfaces or at least using unknown or a more specific type like Record<string, unknown> to maintain type checking.

♻️ Suggested improvement
-    attachments?: any;
+    attachments?: IAttachment[];
-    botData?: any;
+    botData?: Record<string, unknown>;

You may want to define an IAttachment interface based on the expected attachment structure.

Also applies to: 18-18

backend/plugins/frontline_api/src/modules/integrations/instagram/@types/conversations.ts (1)

1-1: Remove unused Schema import.

Schema is imported but never used in this file.

Suggested fix
-import { Document, Schema } from 'mongoose';
+import { Document } from 'mongoose';
backend/plugins/frontline_api/src/modules/integrations/instagram/@types/logs.ts (1)

3-14: Consider replacing any with more specific types or unknown.

Using any for value and specialValue bypasses TypeScript's type checking. If the structure of these fields is truly unknown at compile time, prefer unknown to enforce explicit type narrowing before use. If there are known shapes, consider a union type or generic.

♻️ Suggested improvement
 export interface ILog {
     type: string;
-    value: any;
-    specialValue: any;
+    value: unknown;
+    specialValue: unknown;
     createdAt: Date;
   }
   
   export interface ILogInput {
     type: string;
-    value: any;
-    specialValue: any;
+    value: unknown;
+    specialValue: unknown;
   }
backend/plugins/frontline_api/src/modules/knowledgebase/db/definitions/article.ts (2)

39-39: Consider using Schema.Types.Mixed or a Map schema for reactionCounts.

Using { type: Object } bypasses Mongoose's schema validation. For dynamic key-value data like reaction counts, prefer:

♻️ Suggested refactor
-    reactionCounts: { type: Object }, 
+    reactionCounts: { type: Map, of: Number, default: new Map() },

45-45: Consider using attachmentSchema for pdfAttachment for consistency.

The pdfAttachment field uses { type: Object } which bypasses schema validation. Since attachmentSchema is already imported and used for image and attachments, using it here ensures consistent structure and validation.

♻️ Suggested refactor
-    pdfAttachment: { type: Object }, 
+    pdfAttachment: { type: attachmentSchema },
backend/plugins/frontline_api/src/modules/integrations/instagram/@types/comment_conversations_reply.ts (1)

15-15: Consider replacing any with a more specific type.

Using any bypasses type safety. If the attachment structure is known, define an interface. If it's truly dynamic, consider unknown or Record<string, unknown>[] as safer alternatives.

backend/plugins/frontline_api/src/modules/integrations/instagram/@types/utils.ts (1)

22-25: Add type annotation for schema parameter.

The schema parameter should be typed. Since this is a Mongoose schema utility, consider using the appropriate Mongoose type.

♻️ Suggested fix
+import { Schema } from 'mongoose';
+
-export const schemaWrapper = schema => {
+export const schemaWrapper = <T>(schema: Schema<T>): Schema<T> => {
   schema.add({ scopeBrandIds: [String] });
   return schema;
 };
backend/plugins/frontline_api/src/modules/integrations/instagram/@types/comment_conversations.ts (1)

17-21: isResolved should be typed as boolean.

The field name clearly indicates a boolean state (resolved vs unresolved). Using any loses type safety unnecessarily.

♻️ Suggested fix
 export interface ICommentConversationDocument
   extends ICommentConversation,
     Document {
-  isResolved: any;
+  isResolved: boolean;
 }
backend/plugins/frontline_api/src/modules/knowledgebase/graphql/resolvers/mutations/knowledgeBaseMutations.ts (5)

10-21: Unused subdomain parameter and fetch-only variables.

subdomain is destructured but unused in knowledgeBaseTopicsAdd and knowledgeBaseTopicsRemove. The topic variable on line 45 is also unused. Per coding guidelines, avoid unnecessary declarations.

♻️ Proposed fix
   async knowledgeBaseTopicsAdd(
     _root,
     { doc }: { doc: ITopic },
-    { user, models, subdomain }: IContext
+    { user, models }: IContext
   ) {
   async knowledgeBaseTopicsRemove(
     _root,
     { _id }: { _id: string },
-    { user, models, subdomain }: IContext
+    { models }: IContext
   ) {
-    const topic = await models.Topic.getTopic(_id);
+    await models.Topic.getTopic(_id);
     const removed = await models.Topic.removeDoc(_id);

Also applies to: 40-50


52-79: Unused subdomain and kbCategory variables in category mutations.

Same pattern as Topic mutations: subdomain is destructured but unused, and kbCategory on line 71 is fetched but only used for existence validation.

♻️ Proposed fix
   async knowledgeBaseCategoriesAdd(
     _root,
     { doc }: { doc: ICategoryCreate },
-    { user, models, subdomain }: IContext
+    { user, models }: IContext
   ) {
   async knowledgeBaseCategoriesEdit(
     _root,
     { _id, doc }: { _id: string; doc: ICategoryCreate },
-    { user, models, subdomain }: IContext
+    { user, models }: IContext
   ) {
-    const kbCategory = await models.Category.getCategory(_id);
+    await models.Category.getCategory(_id);
     const updated = await models.Category.updateDoc(

88-91: Simplify $in operator with single value.

Using $in with a single-element array is unnecessary. Use direct equality instead.

♻️ Proposed fix
     await models.Category.updateMany(
-      { parentCategoryId: { $in: [kbCategory._id] } },
+      { parentCategoryId: kbCategory._id },
       { $unset: { parentCategoryId: 1 } }
     );

103-109: Duplicate scheduled date validation logic.

The same validation for scheduled articles appears in both Add and Edit mutations. Extract to a helper function to follow DRY principle. Also, there's inconsistent formatting (if( vs if ().

♻️ Proposed refactor

Extract validation to a helper:

function validateScheduledArticle(doc: IArticleCreate): void {
  if (doc.status === 'scheduled' && !doc.scheduledDate) {
    throw new Error('Scheduled Date must be supplied');
  }
  
  if (doc.status === 'scheduled' && doc.scheduledDate && doc.scheduledDate < new Date()) {
    throw new Error('Scheduled Date can not be in the past!');
  }
}

Then use in both mutations:

   async knowledgeBaseArticlesAdd(
     _root,
     { doc }: { doc: IArticleCreate },
     { user, models }: IContext
   ) {
-    if (doc.status === 'scheduled' && !doc.scheduledDate) {
-      throw new Error('Scheduled Date must be supplied');
-    }
-  
-    if(doc.status === 'scheduled' && doc.scheduledDate && doc.scheduledDate < new Date()){
-      throw new Error('Scheduled Date can not be in the past !');
-    }
+    validateScheduledArticle(doc);

Also applies to: 126-132


98-117: Unused subdomain and fetch-only variables in article mutations.

Consistent with other mutations, subdomain is unused in Add/Edit/Remove. The kbArticle variable on line 149 is also unused.

♻️ Proposed fix for Remove mutation
   async knowledgeBaseArticlesRemove(
     _root,
     { _id }: { _id: string },
-    { user, models, subdomain }: IContext
+    { models }: IContext
   ) {
-    const kbArticle = await models.Article.getArticle(_id);
+    await models.Article.getArticle(_id);
     const removed = await models.Article.removeDoc(_id);
-
-
     return removed;
   },

Also applies to: 144-154

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 17670ab and 5b2d99a.

📒 Files selected for processing (16)
  • backend/plugins/frontline_api/src/modules/integrations/instagram/@types/bots.ts
  • backend/plugins/frontline_api/src/modules/integrations/instagram/@types/comment_conversations.ts
  • backend/plugins/frontline_api/src/modules/integrations/instagram/@types/comment_conversations_reply.ts
  • backend/plugins/frontline_api/src/modules/integrations/instagram/@types/conversationMessages.ts
  • backend/plugins/frontline_api/src/modules/integrations/instagram/@types/conversations.ts
  • backend/plugins/frontline_api/src/modules/integrations/instagram/@types/customers.ts
  • backend/plugins/frontline_api/src/modules/integrations/instagram/@types/logs.ts
  • backend/plugins/frontline_api/src/modules/integrations/instagram/@types/postConversations.ts
  • backend/plugins/frontline_api/src/modules/integrations/instagram/@types/utils.ts
  • backend/plugins/frontline_api/src/modules/integrations/instagram/routes.ts
  • backend/plugins/frontline_api/src/modules/integrations/instagram/utils.ts
  • backend/plugins/frontline_api/src/modules/knowledgebase/db/definitions/article.ts
  • backend/plugins/frontline_api/src/modules/knowledgebase/db/definitions/category.ts
  • backend/plugins/frontline_api/src/modules/knowledgebase/db/definitions/constant.ts
  • backend/plugins/frontline_api/src/modules/knowledgebase/db/definitions/topic.ts
  • backend/plugins/frontline_api/src/modules/knowledgebase/graphql/resolvers/mutations/knowledgeBaseMutations.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • backend/plugins/frontline_api/src/modules/knowledgebase/db/definitions/category.ts
  • backend/plugins/frontline_api/src/modules/knowledgebase/db/definitions/constant.ts
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursorrules)

**/*.{ts,tsx}: Write concise, technical TypeScript code with accurate examples
Use functional and declarative programming patterns; avoid classes
Prefer iteration and modularization over code duplication
Use descriptive variable names with auxiliary verbs (e.g., isLoading, hasError)
Structure files: exported component, utils, contexts, hooks, types
Avoid console logs
Always use absolute paths when importing
Favor named exports for components
Use TypeScript for all code; prefer interfaces over types
Avoid enums; use maps instead
Use functional components with TypeScript interfaces
Use the 'function' keyword for pure functions
Avoid unnecessary curly braces in conditionals; use concise syntax for simple statements

Files:

  • backend/plugins/frontline_api/src/modules/integrations/instagram/@types/comment_conversations.ts
  • backend/plugins/frontline_api/src/modules/integrations/instagram/@types/postConversations.ts
  • backend/plugins/frontline_api/src/modules/integrations/instagram/@types/comment_conversations_reply.ts
  • backend/plugins/frontline_api/src/modules/knowledgebase/db/definitions/topic.ts
  • backend/plugins/frontline_api/src/modules/integrations/instagram/@types/customers.ts
  • backend/plugins/frontline_api/src/modules/integrations/instagram/@types/conversations.ts
  • backend/plugins/frontline_api/src/modules/integrations/instagram/@types/bots.ts
  • backend/plugins/frontline_api/src/modules/knowledgebase/graphql/resolvers/mutations/knowledgeBaseMutations.ts
  • backend/plugins/frontline_api/src/modules/knowledgebase/db/definitions/article.ts
  • backend/plugins/frontline_api/src/modules/integrations/instagram/@types/conversationMessages.ts
  • backend/plugins/frontline_api/src/modules/integrations/instagram/@types/logs.ts
  • backend/plugins/frontline_api/src/modules/integrations/instagram/@types/utils.ts
🧬 Code graph analysis (2)
backend/plugins/frontline_api/src/modules/integrations/instagram/@types/comment_conversations.ts (1)
frontend/libs/ui-modules/src/modules/documents/components/DocumentsInline.tsx (1)
  • Document (14-17)
backend/plugins/frontline_api/src/modules/knowledgebase/graphql/resolvers/mutations/knowledgeBaseMutations.ts (5)
backend/plugins/frontline_api/src/modules/knowledgebase/@types/topic.ts (1)
  • ITopic (4-14)
backend/plugins/frontline_api/src/connectionResolvers.ts (1)
  • IContext (237-241)
backend/plugins/frontline_api/src/modules/knowledgebase/db/models/Category.ts (1)
  • ICategoryCreate (7-9)
backend/plugins/frontline_api/src/modules/knowledgebase/db/models/Article.ts (1)
  • IArticleCreate (9-13)
backend/erxes-api-shared/src/utils/apollo/wrapperResolvers.ts (1)
  • markResolvers (87-94)
⏰ 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). (3)
  • GitHub Check: Sourcery review
  • GitHub Check: frontline_api-ci
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (18)
backend/plugins/frontline_api/src/modules/integrations/instagram/@types/conversationMessages.ts (1)

1-25: LGTM overall!

The interface structure is clean and follows TypeScript conventions. Using interface over type aligns with coding guidelines, and extending mongoose's Document for the document interface is the correct pattern. The explicit _id: string override is appropriate for string-based ID usage.

backend/plugins/frontline_api/src/modules/integrations/instagram/@types/conversations.ts (1)

3-15: LGTM!

The interface definitions follow the project's established pattern for Mongoose document types. The field types are appropriate, and optional fields are correctly marked.

backend/plugins/frontline_api/src/modules/integrations/instagram/@types/logs.ts (1)

16-18: LGTM!

The ILogDocument interface correctly extends both ILog and mongoose's Document, following the standard pattern for Mongoose document types.

backend/plugins/frontline_api/src/modules/integrations/instagram/@types/bots.ts (2)

3-8: Verify that _id: number is intentional for persistent menus.

Mongoose subdocument _id fields are typically ObjectId or string. Using number here suggests these IDs may come from an external system (e.g., Instagram API). If this is intentional, consider adding a brief comment to clarify the source of numeric IDs. Otherwise, consider aligning with the standard string type.


9-25: LGTM!

The IBot and IBotDocument interfaces follow the standard Mongoose + TypeScript pattern correctly. Good use of optional fields for configurable properties.

backend/plugins/frontline_api/src/modules/integrations/instagram/@types/postConversations.ts (1)

4-20: Interface structure looks good.

The interface definitions follow TypeScript best practices with proper use of optional fields and extending Mongoose's Document type.

backend/plugins/frontline_api/src/modules/knowledgebase/db/definitions/article.ts (3)

5-11: LGTM!

The internal formcodesSchema is well-defined with _id: false to avoid unnecessary subdocument IDs.


13-57: Schema structure looks good overall.

The article schema is well-designed with:

  • Proper use of mongooseStringRandomId for _id
  • Required fields for content, status, and title
  • Sensible defaults for status, isPrivate, reactionChoices, and viewCount
  • Timestamps enabled

59-59: Sparse unique index is appropriate for optional code field.

The index correctly allows multiple documents with code: null/undefined while enforcing uniqueness for non-null values.

backend/plugins/frontline_api/src/modules/knowledgebase/db/definitions/topic.ts (1)

4-27: LGTM!

The topic schema is well-structured with:

  • Proper use of mongooseStringRandomId for _id
  • Required title field
  • Correctly typed categoryIds as string array
  • Timestamps enabled
  • Appropriate sparse unique index on code
backend/plugins/frontline_api/src/modules/integrations/instagram/@types/comment_conversations_reply.ts (1)

20-22: LGTM!

The document interface correctly extends both the base interface and Mongoose's Document type, following the standard pattern for typed Mongoose models.

backend/plugins/frontline_api/src/modules/integrations/instagram/@types/customers.ts (2)

1-11: LGTM!

The import and ICustomer interface are well-defined. Using an interface aligns with coding guidelines, and the optional erxesApiId appropriately reflects that this external ID may not exist at creation time.


13-15: LGTM!

The ICustomerDocument correctly extends both ICustomer and Mongoose's Document. Explicitly declaring _id: string is appropriate for working with stringified ObjectIds in application code.

backend/plugins/frontline_api/src/modules/integrations/instagram/@types/utils.ts (1)

27-29: Unused _cacheKey parameter and incomplete hook implementation.

The _cacheKey parameter is accepted but never used, and the function name suggests hook functionality that isn't implemented—it just delegates to schemaWrapper. Is this a placeholder for future functionality, or should the parameter be removed?

Additionally, add type annotation for the schema parameter to maintain consistency.

♻️ Suggested fix (if parameter is intentionally unused for now)
-export const schemaHooksWrapper = (schema, _cacheKey: string) => {
+export const schemaHooksWrapper = <T>(schema: Schema<T>, _cacheKey: string): Schema<T> => {
+  // TODO: Implement cache-key-based hooks if needed
   return schemaWrapper(schema);
 };
backend/plugins/frontline_api/src/modules/integrations/instagram/@types/comment_conversations.ts (2)

1-2: LGTM!

Import of mongoose Document is appropriate for extending document interfaces.


3-15: Remove the suggestion to rename comment_id—it maps directly to external API responses.

The comment_id field is intentionally named in snake_case because it directly corresponds to the Facebook and Instagram API response format. Renaming it to commentId would break the API integration, as the field is referenced throughout the codebase in database queries, GraphQL resolvers, and webhook handlers expecting the snake_case convention. This is not a naming inconsistency but a necessary mapping to an external API contract.

The suggestion to address attachments?: any could still be considered, but ensure the structure aligns with how Instagram actually provides attachment data.

Likely an incorrect or invalid review comment.

backend/plugins/frontline_api/src/modules/knowledgebase/graphql/resolvers/mutations/knowledgeBaseMutations.ts (2)

165-169: Verify intentional permission bypass for all Knowledge Base mutations.

skipPermission: true disables authorization checks for all mutations including Add, Edit, and Remove operations. While this may be intentional for public-facing knowledge bases, it allows any authenticated user to modify content. Confirm this is the intended behavior and consider whether write operations (Add/Edit/Remove) should have different permission requirements than read operations.


8-8: LGTM on export pattern.

Both named and default exports are provided, which allows flexible importing. This aligns with the resolver merging approach mentioned in the AI summary.

Also applies to: 171-171

export interface ICommentConversationReply {
mid: string;
commentConversationId: string;
parentId: String;
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Use primitive type string instead of String.

String refers to the JavaScript constructor/boxed object type, while string is the TypeScript primitive type. All other string fields in this interface correctly use the lowercase primitive.

Suggested fix
-  parentId: String;
+  parentId: string;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
parentId: String;
parentId: string;
🤖 Prompt for AI Agents
In
@backend/plugins/frontline_api/src/modules/integrations/instagram/@types/comment_conversations_reply.ts
at line 6, The field declaration "parentId: String;" uses the boxed JS type;
change it to the TypeScript primitive "parentId: string;" (matching other string
fields in the same interface) so the interface in comment_conversations_reply.ts
uses consistent primitive string types.

content: string;
integrationId: string;
customerId?: string;
permalink_url: String;
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Use primitive type string instead of String.

In TypeScript, string (lowercase) is the primitive type and should be preferred over String (the wrapper object type). This is also inconsistent with line 15 which correctly uses string[].

Proposed fix
-  permalink_url: String;
+  permalink_url: string;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
permalink_url: String;
permalink_url: string;
🤖 Prompt for AI Agents
In
@backend/plugins/frontline_api/src/modules/integrations/instagram/@types/postConversations.ts
at line 14, The property permalink_url in the type declaration uses the wrapper
type String instead of the primitive string; change permalink_url: String to
permalink_url: string in the postConversations type to match idiomatic
TypeScript and the adjacent string[] usage.

Comment on lines 6 to 20
export const field = options => {
const { pkey, type, optional } = options;

if (type === String && !pkey && !optional) {
options.validate = /\S+/;
}

// TODO: remove
if (pkey) {
options.type = String;
options.default = () => nanoid();
}

return options;
};
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Add TypeScript types for function parameters.

The options parameter lacks a type annotation, which violates the coding guidelines requiring TypeScript for all code. Consider defining an interface for the options object.

Also, the TODO: remove comment on line 13 indicates this code block is planned for removal. Should this be addressed now or tracked as a separate issue?

♻️ Suggested type definition
+interface FieldOptions {
+  pkey?: boolean;
+  type?: StringConstructor | NumberConstructor | BooleanConstructor | DateConstructor;
+  optional?: boolean;
+  validate?: RegExp;
+  default?: () => string;
+  [key: string]: unknown;
+}
+
-export const field = options => {
+export const field = (options: FieldOptions): FieldOptions => {
   const { pkey, type, optional } = options;

Would you like me to open an issue to track the TODO on line 13?

🤖 Prompt for AI Agents
In
@backend/plugins/frontline_api/src/modules/integrations/instagram/@types/utils.ts
around lines 6 - 20, The field function’s options parameter is untyped; add a
TypeScript interface (e.g., FieldOptions) that describes pkey?: boolean, type?:
any (or a tighter constructor type), optional?: boolean, validate?: RegExp |
Function, default?: any, etc., then annotate the function as export const field
= (options: FieldOptions) => { ... } and update any usages; leave the existing
pkey-handling block (the "TODO: remove") in place for now but create/track a
separate issue to remove or refactor it later (do not remove it in this change).

Comment on lines +23 to +38
async knowledgeBaseTopicsEdit(
_root,
{ _id, doc }: { _id: string; doc: ITopic },
{ user, models, subdomain }: IContext
) {
const topic = await models.Topic.getTopic(_id);
const updated = await models.Topic.updateDoc(
_id,
doc,
user._id
);

;

return updated;
},
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Stray semicolon and unused variables.

Line 35 contains an isolated semicolon (likely leftover from removed code). Additionally, topic (line 28) and subdomain are unused.

🔧 Proposed fix
   async knowledgeBaseTopicsEdit(
     _root,
     { _id, doc }: { _id: string; doc: ITopic },
-    { user, models, subdomain }: IContext
+    { user, models }: IContext
   ) {
-    const topic = await models.Topic.getTopic(_id);
+    await models.Topic.getTopic(_id);
     const updated = await models.Topic.updateDoc(
       _id,
       doc,
       user._id
     );
 
-;
-
     return updated;
   },
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
async knowledgeBaseTopicsEdit(
_root,
{ _id, doc }: { _id: string; doc: ITopic },
{ user, models, subdomain }: IContext
) {
const topic = await models.Topic.getTopic(_id);
const updated = await models.Topic.updateDoc(
_id,
doc,
user._id
);
;
return updated;
},
async knowledgeBaseTopicsEdit(
_root,
{ _id, doc }: { _id: string; doc: ITopic },
{ user, models }: IContext
) {
await models.Topic.getTopic(_id);
const updated = await models.Topic.updateDoc(
_id,
doc,
user._id
);
return updated;
},
🤖 Prompt for AI Agents
In
@backend/plugins/frontline_api/src/modules/knowledgebase/graphql/resolvers/mutations/knowledgeBaseMutations.ts
around lines 23 - 38, In knowledgeBaseTopicsEdit remove the stray isolated
semicolon after the update call and eliminate unused variables: delete the
unused const topic = await models.Topic.getTopic(_id) (or use its result if
intended), and remove subdomain from the resolver context destructuring if it's
not needed; ensure the function only references models.Topic.updateDoc and
returns updated.

Copy link
Contributor

@ellipsis-dev ellipsis-dev bot left a comment

Choose a reason for hiding this comment

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

Caution

Changes requested ❌

Reviewed efe8ef3 in 3 minutes and 3 seconds. Click for details.
  • Reviewed 1822 lines of code in 34 files
  • Skipped 0 files when reviewing.
  • Skipped posting 11 draft comments. View those below.
  • Modify your settings and rules to customize what types of comments Ellipsis leaves. And don't forget to react with 👍 or 👎 to teach Ellipsis.
1. backend/plugins/frontline_api/src/modules/integrations/instagram/db/models/Bots.ts:227
  • Draft comment:
    Using Math.random() to generate the persistentMenuId for the back button may lead to collisions or non-deterministic behavior. Consider using a more robust ID generator.
  • Reason this comment was not posted:
    Decided after close inspection that this draft comment was likely wrong and/or not actionable: usefulness confidence = 20% vs. threshold = 50% Looking at the context, the back button is special - it has isBackBtn: true in the payload. The regular menu items use _id from the database (line 221), but the back button doesn't have a real database ID since it's dynamically generated. The persistentMenuId: Math.random() appears to be a placeholder value. The comment raises a valid concern about collisions and non-deterministic behavior, but I need to consider: Is this actually used for identification? The isBackBtn: true flag seems to be the real identifier. Without seeing how the payload is processed on the receiving end, I can't be certain if the persistentMenuId value matters for the back button. This seems like a speculative concern without strong evidence of an actual bug. I might be missing that the persistentMenuId could be used for tracking or logging purposes where collisions would matter. The comment could be valid if this ID is used to uniquely identify button clicks in analytics or debugging. However, I don't have evidence from the code that this is the case. Without seeing how the payload is processed or evidence that the persistentMenuId for the back button is actually used for anything important (given that isBackBtn: true is the distinguishing flag), this comment appears speculative. The rule states "Do NOT make speculative comments" and to only keep comments with "STRONG EVIDENCE" that they are correct. This comment is speculative without strong evidence of an actual problem. The back button has isBackBtn: true as its identifier, and the persistentMenuId appears to be a placeholder. Without evidence that this causes actual issues, the comment should be deleted.
2. backend/plugins/frontline_api/src/modules/integrations/instagram/db/models/Bots.ts:146
  • Draft comment:
    Using JSON.stringify for deep comparison in updateBot() can be fragile. Consider using a proper deep equality check to avoid issues if key order changes.
  • Reason this comment was not posted:
    Decided after close inspection that this draft comment was likely wrong and/or not actionable: usefulness confidence = 30% vs. threshold = 50% This is a code quality suggestion about using JSON.stringify for object comparison. While it's true that JSON.stringify can be fragile due to key ordering, in this specific case the developer is creating both objects inline with the same key order, so the comparison should work consistently. The comment is somewhat speculative ("can be fragile") rather than pointing to a definite bug. However, it is an actionable code quality suggestion that could improve the code. The rules say "Comments that suggest code quality refactors are good! But only if they are actionable and clear." This comment is actionable (use a deep equality library) and clear. But I need to consider if this is "obvious or unimportant" - using JSON.stringify for object comparison is a common pattern, though not ideal. The comment doesn't point to a definite issue, just a potential one. The code creates both objects with identical key ordering inline, so the JSON.stringify comparison will work correctly in practice. The comment is somewhat speculative about "issues if key order changes" when the key order is explicitly controlled here. This might be an overly cautious suggestion that doesn't represent a real problem. While the immediate code works, the suggestion is still valid from a code quality perspective - JSON.stringify is generally not the best practice for deep equality checks. However, given that the rules emphasize only keeping comments with "STRONG EVIDENCE" of correctness and to delete speculative comments, this falls into the speculative category since it says "can be fragile" rather than identifying an actual bug. This comment is speculative rather than identifying a definite issue. The code works correctly as written since both objects have the same key order. While it's a reasonable code quality suggestion, it doesn't meet the threshold of "STRONG EVIDENCE" required by the rules, and the rules specifically say to avoid speculative comments.
3. backend/plugins/frontline_api/src/modules/knowledgebase/graphql/resolvers/queries/knowledgeBaseQueries.ts:12
  • Draft comment:
    The buildQuery helper uses key.replace('s','') to derive singular field names. This approach could be error-prone if the key names don't follow a simple pluralization pattern.
  • Reason this comment was not posted:
    Comment was not on a location in the diff, so it can't be submitted as a review comment.
4. backend/plugins/frontline_api/src/modules/integrations/instagram/commonUtils.ts:56
  • Draft comment:
    The getEnv function returns an empty string when an environment variable is missing, which might mask configuration issues. Consider throwing an error or providing a more explicit fallback.
  • Reason this comment was not posted:
    Decided after close inspection that this draft comment was likely wrong and/or not actionable: usefulness confidence = 20% vs. threshold = 50% The comment suggests "consider throwing an error or providing a more explicit fallback" - this is phrased as a suggestion, not a clear bug. The function already has mechanisms to handle missing values (debug logging and a defaultValue parameter). The behavior of returning an empty string appears intentional - it's used throughout the codebase (lines 68, 69, 102, 105, 109, 114). This seems like a code quality/design suggestion rather than identifying a clear bug. The comment uses "might mask configuration issues" which is speculative language. According to the rules, I should not keep speculative comments or code quality suggestions unless they are clearly actionable and identify a definite issue. The function does have a debug log that alerts when a variable is missing, so it's not completely silent. The empty string return might be the intended behavior for this codebase, and changing it to throw errors could break existing functionality. Perhaps the comment has merit as a code quality suggestion. While it could be a valid code quality concern, the comment is phrased speculatively ("might mask") and suggests alternatives without clear evidence that the current approach is wrong. The function already has defensive mechanisms (debug logging, defaultValue parameter). This is more of a design preference than a clear bug. This comment should be deleted. It's a speculative suggestion about design choices rather than identifying a clear bug or required change. The function already has mechanisms to handle missing values, and the empty string return appears to be intentional behavior used throughout the code.
5. backend/plugins/frontline_api/src/connectionResolvers.ts:467
  • Draft comment:
    There's an extra space between the closing parenthesis and the final parenthesis in the call to loadInstagramBotClass(models) on line 467. Please remove the extra whitespace.
  • Reason this comment was not posted:
    Decided after close inspection that this draft comment was likely wrong and/or not actionable: usefulness confidence = 10% vs. threshold = 50% This is a whitespace/formatting issue. The comment is technically correct - there is an extra space on line 467. However, this falls into the category of "obvious or unimportant" comments. Whitespace inconsistencies like this are typically: 1. Caught by linters/formatters automatically 2. Very minor style issues that don't affect functionality 3. Not worth human review time The rules explicitly state "Do NOT make comments that are obvious or unimportant." A single extra space before a semicolon is both obvious (if you're looking for it) and unimportant (doesn't affect code behavior). This would likely be caught by automated formatting tools. Could this whitespace inconsistency indicate a larger pattern issue or be part of the project's strict style guidelines? Maybe the project doesn't use automated formatters and relies on manual review for consistency? Even if the project has strict style guidelines, this type of trivial whitespace issue is exactly what automated tools are designed to catch. The rules explicitly say not to comment on obvious or unimportant issues, and a single extra space clearly falls into that category. If this were important, it would be caught by CI/linting. This comment should be deleted. It points out a trivial whitespace inconsistency that is both obvious and unimportant. Such issues should be handled by automated formatting tools, not manual code review comments.
6. backend/plugins/frontline_api/src/modules/integrations/instagram/db/models/Bots.ts:14
  • Draft comment:
    Typo: The error message "Please provide a name of bot" could be rephrased as "Please provide the bot's name" for better clarity.
  • Reason this comment was not posted:
    Decided after close inspection that this draft comment was likely wrong and/or not actionable: usefulness confidence = 15% vs. threshold = 50% This comment is about a minor grammatical improvement to an error message. While the suggested wording is slightly better, this falls into the category of "obvious or unimportant" comments according to the rules. The original message is perfectly understandable, and this is a very minor stylistic preference. The rules explicitly state "Do NOT make comments that are obvious or unimportant." Error message wording tweaks like this are typically not critical enough to warrant blocking or commenting on a PR unless they are confusing or incorrect - which this one is not. The original message clearly communicates what's needed. Could this be considered an actionable code quality improvement? Some teams do care about consistent, polished error messages for user experience. The comment does provide a concrete suggestion. While some teams care about error message quality, this is such a minor stylistic change that it falls below the threshold of importance. The original message is clear and functional. The rules emphasize not making obvious or unimportant comments, and a minor grammatical preference on an already-clear error message fits that category. This comment should be deleted. It's a minor stylistic suggestion on an error message that is already clear and understandable. This falls under the "obvious or unimportant" category of comments that should not be made.
7. backend/plugins/frontline_api/src/modules/integrations/instagram/db/models/Bots.ts:98
  • Draft comment:
    Typo: The error message "Not found account" can be improved to "Account not found" for clarity.
  • Reason this comment was not posted:
    Decided after close inspection that this draft comment was likely wrong and/or not actionable: usefulness confidence = 15% vs. threshold = 50% This comment is suggesting a grammatical improvement to an error message. According to the rules, I should not comment on things that are "obvious or unimportant." While the suggested change does improve the grammar slightly, this is a very minor stylistic preference. The original message "Not found account" is understandable, even if not perfectly grammatical. This falls into the category of an unimportant comment - it's not fixing a bug, it's not improving code logic, it's just a minor wording preference. The rules explicitly state "Do NOT make comments that are obvious or unimportant." This is clearly in the "unimportant" category. Could this be considered a valuable code quality improvement? Error messages are user-facing (or developer-facing) and having clear, grammatically correct messages could be considered good practice. Perhaps this isn't as trivial as I initially thought. While clear error messages are important, the difference between "Not found account" and "Account not found" is so minor that it doesn't meaningfully impact clarity or understanding. The original message is perfectly comprehensible. This is a nitpick about grammar, not a substantive improvement to code quality or functionality. This comment should be deleted. It's a minor grammatical suggestion that falls under "obvious or unimportant" comments. The original error message is clear enough, and this level of nitpicking about wording doesn't provide sufficient value to warrant a review comment.
8. backend/plugins/frontline_api/src/modules/integrations/instagram/db/models/Comment_conversations.ts:7
  • Draft comment:
    Typographical issue: It looks like the import on this line is missing a semicolon at the end. Consider adding a semicolon for consistency.
  • Reason this comment was not posted:
    Decided after close inspection that this draft comment was likely wrong and/or not actionable: usefulness confidence = 20% vs. threshold = 50% This is a style/formatting issue about a missing semicolon. While it's technically correct that the semicolon is missing and inconsistent with other imports in the file, I need to consider if this would be caught by linting tools or if it's too minor. The rules say "Do NOT make comments that are obvious or unimportant." A missing semicolon is typically caught by linters/formatters like ESLint or Prettier, which would be part of the build process. The rule states "Do NOT comment on anything that would be obviously caught by the build." This would likely be caught by automated tooling. However, not all projects have strict linting enabled, and some TypeScript projects allow semicolons to be optional. If the linter isn't configured to enforce this, it might not be caught automatically. The comment does point out a real inconsistency within the file itself. While it's true that linting might not be configured, the general principle is that formatting issues like missing semicolons are typically handled by automated tools in modern development workflows. This is a minor, obvious formatting issue that should be caught by standard tooling, making it fall under the "obvious or unimportant" category. This comment should be deleted. It's a minor formatting issue (missing semicolon) that would typically be caught by linters or formatters during the build process, falling under the rule about not commenting on things obviously caught by the build.
9. backend/plugins/frontline_api/src/modules/integrations/instagram/db/models/Integrations.ts:17
  • Draft comment:
    Typographical error: There is an extra trailing space in the error message string ('Instagram Integration not found '). Please remove the extra space.
  • Reason this comment was not posted:
    Decided after close inspection that this draft comment was likely wrong and/or not actionable: usefulness confidence = 35% vs. threshold = 50% This is a very minor code quality issue - a trailing space in an error message. The rules say "Do NOT make comments that are obvious or unimportant" and "Do NOT comment unless there is clearly a code change required." A trailing space in an error message is cosmetic and doesn't affect functionality. While it's technically correct, it's arguably unimportant and obvious. However, the rules also say "Comments that suggest code quality refactors are good! But only if they are actionable and clear." This comment is actionable and clear. The question is whether removing a trailing space counts as important enough to warrant a comment. This is a legitimate code quality issue that improves consistency and cleanliness. While minor, trailing spaces in strings are generally considered poor practice and should be removed. The comment is actionable, clear, and even provides a suggestion. It's not speculative or asking for confirmation - it's pointing out a definite issue. While the comment is technically correct and actionable, the issue is extremely minor and could be considered "unimportant" per the rules. The trailing space doesn't affect functionality and is the kind of thing that might be caught by a linter. However, it's a clear improvement to code quality and the comment is well-formed with a concrete suggestion. This is a borderline case. The comment identifies a real but very minor issue (trailing space in error message). It's actionable and clear, but arguably falls under "obvious or unimportant." Given the instruction to err on the side of deleting comments when unsure, and that this is a trivial cosmetic issue, I'll lean toward deletion but with moderate confidence.
10. backend/plugins/frontline_api/src/modules/integrations/instagram/utils.ts:404
  • Draft comment:
    Typo in comment: "Insert the user's name dynamically into the messa"—"messa" should be "message".
  • Reason this comment was not posted:
    Decided after close inspection that this draft comment was likely wrong and/or not actionable: usefulness confidence = 20% vs. threshold = 50% This is a comment about a typo in a code comment (not in actual code logic). The rules state "Do NOT make comments that are obvious or unimportant." A typo in a comment is relatively minor - it doesn't affect functionality. However, the rules also say "Comments that suggest code quality refactors are good! But only if they are actionable and clear." This is actionable and clear, but it's debatable whether fixing a typo in a comment counts as a meaningful code quality improvement. The rules emphasize not commenting unless there's "clearly a code change required" - fixing comment typos is arguably not a required change. This seems like a very minor issue that falls into the "obvious or unimportant" category. While typos should ideally be fixed, this is an extremely minor issue in a comment (not code) that doesn't affect functionality. The rules explicitly state not to make obvious or unimportant comments, and a truncated word in a comment could be considered unimportant since it doesn't impact the code's behavior. Although fixing typos improves code quality and readability, the rules prioritize avoiding minor/obvious comments. This typo doesn't create confusion about what the code does, and the comment is still understandable. Given the emphasis on only keeping comments with "STRONG EVIDENCE" of being correct and necessary, a comment typo fix is likely too minor to warrant keeping. This comment should be deleted. While technically correct, it points out a minor typo in a code comment that doesn't affect functionality or create real confusion. This falls under "obvious or unimportant" comments that should not be made according to the rules.
11. backend/plugins/frontline_api/src/modules/integrations/instagram/utils.ts:194
  • Draft comment:
    Typo in function name: "refreshPageAccesToken" should be "refreshPageAccessToken".
  • Reason this comment was not posted:
    Marked as duplicate.

Workflow ID: wflow_lCfvIOM9aCIziWvW

You can customize Ellipsis by changing your verbosity settings, reacting with 👍 or 👎, replying to comments, or adding code review rules.

public static async getIntegration(selector) {
// const integration = await models.Integrations.findOne(selector);

const integration = await models.Integrations.findOne();
Copy link
Contributor

Choose a reason for hiding this comment

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

getIntegration() ignores the passed selector and always calls findOne() without filtering. Consider using the selector argument (e.g. use findOne(selector)) to correctly filter integrations.

Suggested change
const integration = await models.Integrations.findOne();
const integration = await models.Integrations.findOne(selector);


try {
const response: any = await graphRequest.get(
`/${postId}?fields=permalink_url,message,created_time,`,
Copy link
Contributor

Choose a reason for hiding this comment

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

The getPostDetails request string includes a trailing comma in the fields parameter. Remove the trailing comma to ensure the query returns valid data.

Suggested change
`/${postId}?fields=permalink_url,message,created_time,`,
`/${postId}?fields=permalink_url,message,created_time`,


export const getProfile = async (facebookPageId: string, accessToken?: any) => {
const accounInfo: any = await graphRequest.get(
`${facebookPageId}?fields=profile_picture_url,username
Copy link
Contributor

Choose a reason for hiding this comment

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

The getProfile function’s query string spans multiple lines with a newline character. This may introduce unwanted whitespace in the URL. Consider ensuring the URL string is trimmed or defined in a single line.

throw error;
}
};
export const refreshPageAccesToken = async (
Copy link
Contributor

Choose a reason for hiding this comment

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

The function name refreshPageAccesToken is misspelled. Consider renaming it to refreshPageAccessToken for clarity and consistency.

}

if (!doc.accountId) {
throw new Error("Please select a instagram account");
Copy link
Contributor

Choose a reason for hiding this comment

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

Typo: In the error message "Please select a instagram account", consider updating it to "Please select an Instagram account" (note the article change and capitalization).

Suggested change
throw new Error("Please select a instagram account");
throw new Error("Please select an Instagram account");

}

if (!doc.pageId) {
throw new Error("Please select a instagram page");
Copy link
Contributor

Choose a reason for hiding this comment

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

Typo: In the error message "Please select a instagram page", consider updating it to "Please select an Instagram page" (note the article change and capitalization).

Suggested change
throw new Error("Please select a instagram page");
throw new Error("Please select an Instagram page");


export const debugInit = debug('erxes-integrations:init');
export const debugDb = debug('erxes-integrations:db');
export const debugCrons = debug('erxes-integrations-crons:');
Copy link
Contributor

Choose a reason for hiding this comment

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

Typo: The debug string for debugCrons reads 'erxes-integrations-crons:' but all other debug constants follow the 'erxes-integrations:<name>' pattern. Consider changing it to 'erxes-integrations:crons' if that's the intended naming.

Suggested change
export const debugCrons = debug('erxes-integrations-crons:');
export const debugCrons = debug('erxes-integrations:crons');

return response;
} catch (e) {
debugError(
`Error ocurred while trying to send post request to instagram ${
Copy link
Contributor

Choose a reason for hiding this comment

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

Typo: "Error ocurred" should be "Error occurred".

Suggested change
`Error ocurred while trying to send post request to instagram ${
`Error occurred while trying to send post request to instagram ${

return response;
} catch (e) {
debugError(
`Error ocurred while trying to send post request to facebook ${
Copy link
Contributor

Choose a reason for hiding this comment

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

Typo: "Error ocurred" should be "Error occurred".

Suggested change
`Error ocurred while trying to send post request to facebook ${
`Error occurred while trying to send post request to facebook ${

for (const page of response.data) {
if (page.instagram_business_account) {
const pageId = page.instagram_business_account.id;
const accounInfo: any = await graphRequest.get(
Copy link
Contributor

Choose a reason for hiding this comment

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

Typo in variable name: accounInfo is likely intended to be accountInfo. Please update for consistency (also check occurrences at lines 285 and 297).

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

Note

Due to the large number of review comments, Critical, Major severity comments were prioritized as inline comments.

🤖 Fix all issues with AI agents
In
@backend/plugins/frontline_api/src/modules/integrations/instagram/@types/accounts.ts:
- Around line 3-13: The TypeScript interface IInstagramAccount is out of sync
with the persistence schema (accountSchema) — it declares username? and a
required email that the schema does not define; update either the interface or
the schema so they match: if email and username should be stored, add those
fields to accountSchema with correct types and optional/required flags and
update any validation; otherwise remove username and email from
IInstagramAccount (or make email optional) to reflect the schema. Locate
IInstagramAccount in accounts.ts and the corresponding accountSchema definition
and make the change consistently across code that reads/writes Instagram
accounts.

In
@backend/plugins/frontline_api/src/modules/integrations/instagram/db/definitions/accounts.ts:
- Around line 11-22: The schema fields tokenSecret, scope, and expireDate are
using an invalid Mongoose option `optional: true`; remove the `optional` entries
(fields are optional by default) or replace with `required: true` where you
intend a mandatory field; update the object definitions for tokenSecret, scope,
and expireDate in the accounts schema (remove `optional: true` from each or
switch to `required: true` as appropriate) so the schema uses valid Mongoose
options.

In
@backend/plugins/frontline_api/src/modules/integrations/instagram/db/definitions/bots.ts:
- Line 23: The createdAt field in the schema uses Date.now() which is evaluated
at schema-definition time; change the default to the function reference Date.now
(no parentheses) in the bots schema definition (the createdAt property in this
file) so a fresh timestamp is generated when each document is created.

In
@backend/plugins/frontline_api/src/modules/integrations/instagram/db/definitions/comment_conversations.ts:
- Around line 5-19: The commentConversationSchema is missing the isResolved
field declared on IInstagramCommentConversationDocument; add isResolved to
commentConversationSchema with type Boolean and default: false (matching
commentConversationReplySchema) so the schema and interface stay consistent and
new conversations default to unresolved.

In
@backend/plugins/frontline_api/src/modules/integrations/instagram/db/models/Bots.ts:
- Around line 89-127: The repair method mutates bot.token and bot.accountId but
never persists them; after updating those fields (in the branch that finds
relatedAccount) call and await a save/update on the bot record (e.g., await
bot.save() or models.Bots.updateOne({ _id: bot._id }, { token: bot.token,
accountId: bot.accountId })) before calling connectBotPageMessenger so the
repaired values are stored; also propagate/handle any save errors consistently
with the existing try/catch around connectBotPageMessenger.
- Around line 267-270: disconnectBotPageMessenger currently deletes the bot
record (models.InstagramBots.deleteOne) but should only disconnect messenger
configuration; change disconnectBotPageMessenger to remove messenger-specific
config instead of deleting the document: call the messenger/FB API client to
clear persistent menus/greetings (or wrap that in a helper like
removeMessengerConfiguration), then update the InstagramBots document (e.g.,
using models.InstagramBots.updateOne or findByIdAndUpdate) to unset or nullify
messenger-related fields (persistentMenu, greeting, pageId, accessToken, etc.),
and return success; do not call deleteOne or duplicate removeBot logic—reuse any
existing removeMessenger helper if available and reference
disconnectBotPageMessenger and removeBot for locating the relevant logic.
- Around line 196-265: connectBotPageMessenger builds the messenger profile
payload (doc) but never posts it to the API and uses Math.random() for
back-button IDs; fix by making a POST request with the constructed doc (e.g.,
call graphRequest.post('/me/messenger_profile', pageAccessToken, doc) or the
equivalent graph client used elsewhere) and return/propagate the API response,
and replace Math.random() for persistentMenuId with a deterministic/safer
identifier (e.g., use the existing persistent menu _id when available or
generate a UUID via crypto.randomUUID() / a UUID library) so payload IDs are
stable and collision-resistant; ensure errors from the post are caught/logged
and the method returns meaningful success/failure information instead of always
{ status: "success" }.

In
@backend/plugins/frontline_api/src/modules/integrations/instagram/db/models/Configs.ts:
- Around line 19-27: getConfig currently returns a plain object { value: '' }
when no record is found, which breaks the expected IInstagramConfigDocument
return type and also mismatches the schema where value is an Object; change
getConfig (in Configs.getConfig) to return null when not found and update its
TypeScript signature to Promise<IInstagramConfigDocument | null>, then update
any callers to handle null (or alternatively return a document-shaped object
matching IInstagramConfigDocument with value as an object), ensuring consistency
with the schema's value type.
- Line 20: The Instagram config methods are querying the wrong collection by
using models.Configs; replace every usage of models.Configs with
models.InstagramConfig in this file so the Instagram-specific model is used.
Specifically update the calls that reference models.Configs.findOne, findAll,
create, update (or save), and destroy/delete in the Instagram config helper
functions to use models.InstagramConfig.findOne, models.InstagramConfig.findAll,
models.InstagramConfig.create, models.InstagramConfig.update (or instance save),
and models.InstagramConfig.destroy/delete so they operate on the
instagram_configs collection.

In
@backend/plugins/frontline_api/src/modules/integrations/instagram/db/models/Integrations.ts:
- Around line 12-21: getIntegration currently ignores the selector and always
calls models.Integrations.findOne() which returns the first document; change
getIntegration to pass the selector into findOne (i.e.,
models.Integrations.findOne(selector)) so it returns the matching integration,
preserve the existing not-found throw, and also verify whether the code should
query models.InstagramIntegrations instead of models.Integrations and update the
model reference if the Instagram-specific collection is appropriate.

In
@backend/plugins/frontline_api/src/modules/integrations/instagram/debuggers.ts:
- Around line 24-34: Add TypeScript types to the debug functions: annotate
debugRequest and debugResponse parameters so debugInstance is typed as a (msg:
string) => void and req is typed as Express's Request (import Request from
'express'); give data in debugResponse a specific type (e.g., string | unknown)
and a default of 'success'. Also guard against undefined origin by resolving a
safe origin string (e.g., const origin = req.headers.origin ?? req.get('host')
?? 'unknown') and use that in the log messages so logs never show "undefined".
Ensure the functions debugRequest and debugResponse signatures reflect these
types and import Request where needed.

In @backend/plugins/frontline_api/src/modules/integrations/instagram/types.ts:
- Around line 27-38: postback and comments are declared as required
identical-structured objects but they should be optional and deduplicated;
define a shared interface (e.g., InstagramMessageDetail or
SharedInstagramPayload) capturing { title: string; mid: string; payload: string;
quick_reply?: any } then change the types for postback and comments to use this
interface and mark them optional (postback?: InstagramMessageDetail; comments?:
InstagramMessageDetail); update any imports/usages of postback/comments
accordingly.

In @backend/plugins/frontline_api/src/modules/integrations/instagram/utils.ts:
- Around line 304-425: Extract the shared integration lookup and token retrieval
into a helper (e.g., getIntegrationPageToken(models, integrationId) that returns
{ integration, pageAccessToken }) and update sendReply and sendReplyComment to
call that helper instead of duplicating the logic; replace the try/catch blocks
that currently return the caught error (e.g., the catch branches in sendReply
and sendReplyComment) with thrown Errors so callers receive exceptions
consistently; and fix the log message in sendReplyComment that incorrectly says
"facebook" to "instagram" (the debugError/debugInstagram call that mentions
facebook). Ensure helper validates integration existence, facebookPageId, and
pageAccessToken and throws descriptive Errors when missing.
- Around line 9-35: Update the hard-coded deprecated API version in
graphRequest.base by replacing graph.setVersion("19.0") with a supported version
(e.g., graph.setVersion("22.0") or "21.0") and ensure all calls use that
version; also strengthen types by changing base signature to accept method:
'get' | 'post' | 'del', typed path/accessToken parameters, and a typed Promise
return (replace all any usages in graphRequest.base and the get/post/delete
wrappers with appropriate interfaces for request params and response shape) so
graphRequest.get/post/delete return a correctly typed response.

In
@backend/plugins/frontline_api/src/modules/knowledgebase/graphql/resolvers/customResolvers/category.ts:
- Around line 65-72: Rename the invalid plural field `childrens` to `children`
in both the GraphQL schema definition (change the field name in the type defs)
and the resolver object property (update KnowledgeBaseParentCategory's async
childrens(...) to async children(...)), update any internal
references/imports/usages to the new `children` name (including tests and other
resolvers), and run schema validation/GraphQL build to ensure no remaining
references to `childrens` remain; treat this as a breaking change for API
consumers and bump/change docs accordingly.
🟡 Minor comments (18)
backend/plugins/frontline_api/src/modules/integrations/instagram/db/definitions/conversationMessages.ts-20-21 (1)

20-21: Inconsistent formatting: missing space after colon.

Line 20 has label:'Created At' while line 21 has label: 'Updated At'. Add a space after the colon for consistency.

Suggested fix
-    createdAt: { type: Date, index: true, label:'Created At' },
+    createdAt: { type: Date, index: true, label: 'Created At' },
backend/plugins/frontline_api/src/modules/integrations/instagram/db/definitions/conversations.ts-14-14 (1)

14-14: optional is not a valid Mongoose schema option.

Mongoose does not recognize optional as a schema type option—it will be silently ignored. All Mongoose fields are optional (not required) by default, so you can simply remove this property. If you need to explicitly mark a field as required, use required: true.

🔧 Suggested fix
-    botId: { type: String, optional: true }
+    botId: String
backend/plugins/frontline_api/src/modules/integrations/instagram/debuggers.ts-5-5 (1)

5-5: Inconsistent namespace format.

Line 5 uses erxes-integrations-crons: (hyphen before crons) while all other namespaces follow the erxes-integrations:* pattern with a colon separator. This inconsistency will affect filtering when enabling debug output via the DEBUG environment variable.

Suggested fix
-export const debugCrons = debug('erxes-integrations-crons:');
+export const debugCrons = debug('erxes-integrations:crons');
backend/plugins/frontline_api/src/modules/integrations/instagram/db/definitions/comment_conversations_reply.ts-14-15 (1)

14-15: Invalid Mongoose schema option: optional is not recognized.

Both customerId and userId use optional: true, which is not a valid Mongoose option. Fields are optional by default.

Proposed fix
-    customerId: { type: String, optional: true },
-    userId: { type: String, optional: true },
+    customerId: { type: String },
+    userId: { type: String },
backend/plugins/frontline_api/src/modules/integrations/instagram/db/definitions/postConversations.ts-14-14 (1)

14-14: Invalid Mongoose schema option: optional is not recognized.

Mongoose schemas use required: true/false, not optional. The optional: true property will be silently ignored. Since fields are optional by default in Mongoose, you can simply remove this property or use required: false explicitly if you want to be explicit.

Proposed fix
-    customerId: { type: String, optional: true },
+    customerId: { type: String },
backend/plugins/frontline_api/src/modules/integrations/instagram/db/definitions/comment_conversations.ts-15-15 (1)

15-15: Invalid Mongoose schema option: optional is not recognized.

Same issue as in postConversations.ts. Mongoose uses required, not optional.

Proposed fix
-    customerId: { type: String, optional: true },
+    customerId: { type: String },
backend/plugins/frontline_api/src/modules/integrations/instagram/db/definitions/customers.ts-4-12 (1)

4-12: Use schemaWrapper for consistency with other Instagram schemas and add the processId field.

Most Instagram db/definitions modules use schemaWrapper from erxes-api-shared. This file should follow the same pattern. The schemaWrapper utility adds a processId field and ensures consistent schema structure across the module.

Additionally, since integrationId and erxesApiId are actively used in queries, consider adding indexes for improved query performance.

backend/plugins/frontline_api/src/modules/integrations/instagram/types.ts-41-53 (1)

41-53: Document the purpose and scope of attachment interfaces.

IAttachment, IAttachmentMessage, and IMessageData.message.attachments represent attachments in three different contexts: flat input format, API request wrapper format, and generic incoming message payload. While the generateAttachmentMessages function correctly transforms IAttachment[] into IAttachmentMessage[] for Instagram/Facebook API compatibility, the lack of documentation on when each interface should be used could confuse future maintainers. Consider adding inline comments or JSDoc clarifying that IAttachment is the input format, IAttachmentMessage is the API message wrapper, and IMessageData.message.attachments is for incoming messages.

backend/plugins/frontline_api/src/modules/knowledgebase/graphql/resolvers/customResolvers/category.ts-6-21 (1)

6-21: Type mismatch: query.status changes from object to string.

The query.status is initially typed as { $in: string[] } but gets reassigned to status (a string) on line 15. This causes a type inconsistency. Additionally, args lacks type annotation.

🔧 Suggested fix
-  async articles(category: ICategoryDocument, args, { models }: IContext) {
-    const { status } = args;
-    const query = {
+  async articles(category: ICategoryDocument, args: { status?: string }, { models }: IContext) {
+    const { status } = args;
+    const query: { categoryId: string; status: string | { $in: string[] } } = {
       categoryId: category._id,
       status: {
         $in: [PUBLISH_STATUSES.PUBLISH, PUBLISH_STATUSES.DRAFT],
       },
     };
     if (status) {
       query.status = status;
     }
backend/plugins/frontline_api/src/modules/integrations/instagram/utils.ts-194-194 (1)

194-194: Typo in function name.

refreshPageAccesToken should be refreshPageAccessToken (missing 's' in "Access").

backend/plugins/frontline_api/src/modules/integrations/instagram/utils.ts-296-303 (1)

296-303: Unintended newline in API query string.

The template literal on lines 298-300 contains a newline character in the fields parameter which may cause unexpected API behavior.

Proposed fix
 export const getProfile = async (facebookPageId: string, accessToken?: any) => {
   const accounInfo: any = await graphRequest.get(
-    `${facebookPageId}?fields=profile_picture_url,username
-`,
+    `${facebookPageId}?fields=profile_picture_url,username`,
     accessToken
   );
   return accounInfo;
 };
backend/plugins/frontline_api/src/modules/integrations/instagram/utils.ts-75-93 (1)

75-93: Empty error message and trailing comma in API fields.

Line 79 throws an error with no message, making debugging impossible. Line 84 has a trailing comma in the fields parameter which may cause unexpected API behavior.

Proposed fix
   } catch (e) {
     debugError(`Error occurred while getting page access token: ${e.message}`);
-    throw new Error();
+    throw new Error(`Failed to get page access token: ${e.message}`);
   }

   try {
     const response: any = await graphRequest.get(
-      `/${postId}?fields=permalink_url,message,created_time,`,
+      `/${postId}?fields=permalink_url,message,created_time`,
       pageAccessToken
     );
backend/plugins/frontline_api/src/modules/integrations/instagram/utils.ts-189-192 (1)

189-192: Replace console.error with debug utility.

Line 190 uses console.error which violates the coding guideline "Avoid console logs". Use the existing debugError utility instead for consistency.

Proposed fix
   } catch (error) {
-    console.error("Error fetching Page Access Token:", error.message);
+    debugError(`Error fetching Page Access Token: ${error.message}`);
     throw error;
   }
backend/plugins/frontline_api/src/modules/integrations/instagram/utils.ts-54-67 (1)

54-67: Inconsistent null handling may cause runtime errors.

fetchPagesPostsList and fetchPagePosts access response.data without first checking if response is defined, unlike fetchPagePost which handles null. If the API returns an unexpected response, this will throw.

Proposed fix
-  return response.data || [];
+  return response?.data || [];

Apply to both lines 58 and 66.

backend/plugins/frontline_api/src/modules/integrations/instagram/utils.ts-398-406 (1)

398-406: Missing error handling for user lookup.

The API call to fetch user info (lines 399-401) is not wrapped in a try-catch. If this request fails, the function will throw with an unclear error message, making debugging difficult.

Proposed fix
   const user = data.senderId;
+  let name: string;
+  try {
     const nameResponse = await graphRequest.get(
       `/${user}?fields=name,username&access_token=${pageAccessToken}`
     );
-  const name = nameResponse.username || nameResponse.name;
+    name = nameResponse.username || nameResponse.name;
+  } catch (e) {
+    debugError(`Error fetching user info for reply: ${e.message}`);
+    throw new Error(`Failed to fetch user info: ${e.message}`);
+  }
backend/plugins/frontline_api/src/modules/integrations/instagram/db/definitions/bots.ts-9-9 (1)

9-9: optional: true is not valid Mongoose schema syntax.

Mongoose uses required: true/false, not optional. Fields are optional by default, so you can simply remove optional: true or use required: false if you want to be explicit.

This also applies to lines 21, 22, 24, and 25.

Proposed fix
-    link: { type: String, optional: true },
+    link: { type: String },

And similarly for other fields with optional: true.

backend/plugins/frontline_api/src/modules/integrations/instagram/db/models/Configs.ts-32-48 (1)

32-48: Type mismatch: value typed as string[] but schema defines it as Object.

The createOrUpdateConfig method types value as string[], but the config schema defines value as { type: Object }. This type inconsistency could cause unexpected behavior.

Proposed fix
       public static async createOrUpdateConfig({
         code,
         value
       }: {
         code: string;
-        value: string[];
+        value: unknown;
       }) {
backend/plugins/frontline_api/src/modules/integrations/instagram/db/models/Bots.ts-227-237 (1)

227-237: Avoid using Math.random() for identifiers.

Math.random() does not guarantee uniqueness and is not reproducible. Use a proper ID generation approach.

🐛 Suggested fix
       if (isEnabledBackBtn) {
         generatedPersistentMenus.push({
           type: "postback",
           title: backButtonText || "Back",
           payload: JSON.stringify({
             botId,
             isBackBtn: true,
-            persistentMenuId: Math.random()
+            persistentMenuId: `back_btn_${botId}`
           })
         });
       }
🧹 Nitpick comments (35)
backend/plugins/frontline_api/src/modules/integrations/instagram/constants.ts (3)

1-6: Derive ALL from the defined constants to avoid duplication.

The ALL array duplicates the string literals instead of referencing the constants. If a value changes (e.g., ERROR: 'err'), the ALL array would need a manual update, risking inconsistency.

♻️ Suggested refactor
-export const LOG_TYPES = {
-    ERROR: 'error',
-    REGULAR: 'regular',
-    SUCCESS: 'success',
-    ALL: ['error', 'regular', 'success']
-  };
+export const LOG_TYPES = {
+  ERROR: 'error',
+  REGULAR: 'regular',
+  SUCCESS: 'success',
+} as const;
+
+export const LOG_TYPES_ALL = Object.values(LOG_TYPES);

Alternatively, if you need ALL within the object:

const LOG_TYPE_VALUES = {
  ERROR: 'error',
  REGULAR: 'regular',
  SUCCESS: 'success',
} as const;

export const LOG_TYPES = {
  ...LOG_TYPE_VALUES,
  ALL: Object.values(LOG_TYPE_VALUES),
};

8-12: Same DRY concern applies here.

The ALL array duplicates literal strings. Additionally, note the order mismatch: constants are declared MESSENGER then POST, but ALL lists 'instagram-post' before 'instagram-messenger'.

♻️ Suggested refactor
-  export const INTEGRATION_KINDS = {
-    MESSENGER: 'instagram-messenger',
-    POST: 'instagram-post',
-    ALL: ['instagram-post', 'instagram-messenger']
-  };
+export const INTEGRATION_KINDS = {
+  MESSENGER: 'instagram-messenger',
+  POST: 'instagram-post',
+} as const;
+
+export const INTEGRATION_KINDS_ALL = Object.values(INTEGRATION_KINDS);

14-20: Consider adding as const for better type inference.

The array is fine, but adding as const would provide a readonly tuple type with literal string types, improving type safety when used elsewhere.

♻️ Suggested refactor
-  export const INSTAGRAM_POST_TYPES = [
-    'status',
-    'video',
-    'photo',
-    'post',
-    'share'
-  ];
+export const INSTAGRAM_POST_TYPES = [
+  'status',
+  'video',
+  'photo',
+  'post',
+  'share',
+] as const;
backend/plugins/frontline_api/src/modules/integrations/instagram/db/definitions/logs.ts (2)

3-3: Use absolute path for import.

The relative import '../../constants' violates the coding guideline requiring absolute paths. As per coding guidelines, this should use an absolute path consistent with other imports in the codebase.

♻️ Suggested fix
-import { LOG_TYPES } from '../../constants';
+import { LOG_TYPES } from 'backend/plugins/frontline_api/src/modules/integrations/instagram/constants';

11-11: Add default value for createdAt.

The createdAt field lacks a default value, so logs won't be automatically timestamped unless the caller explicitly provides the date. This could result in missing timestamps.

♻️ Suggested fix
-    createdAt: { type: Date },
+    createdAt: { type: Date, default: Date.now },
backend/plugins/frontline_api/src/modules/integrations/instagram/db/definitions/conversationMessages.ts (2)

3-4: Consolidate imports from the same module.

Both mongooseStringRandomId and schemaWrapper are imported from erxes-api-shared/utils. Combine them into a single import statement.

Suggested fix
-import { mongooseStringRandomId } from 'erxes-api-shared/utils';
-import { schemaWrapper } from 'erxes-api-shared/utils';
+import { mongooseStringRandomId, schemaWrapper } from 'erxes-api-shared/utils';

11-12: Consider removing redundant single-field indexes.

The compound indexes { conversationId: 1, createdAt: -1 } and { customerId: 1, createdAt: -1 } can satisfy queries on just conversationId or customerId respectively (index prefix property). The individual index: true on these fields creates redundant indexes that consume storage and add write overhead.

Suggested fix
-    conversationId: { type: String, index: true },
-    customerId: { type: String, index: true },
+    conversationId: { type: String },
+    customerId: { type: String },

Also applies to: 29-30

backend/plugins/frontline_api/src/modules/integrations/instagram/db/models/Comment_conversations.ts (1)

11-12: Consider stronger typing for selector parameter.

Using any for the selector parameter loses type safety. Consider using Mongoose's FilterQuery type for better IDE support and compile-time checks.

Proposed improvement
+import { FilterQuery } from 'mongoose';
+
 export interface IInstagramCommentConversationModel
   extends Model<IInstagramCommentConversationDocument> {
-  getCommentConversation(selector: any): Promise<IInstagramCommentConversationDocument>;
+  getCommentConversation(selector: FilterQuery<IInstagramCommentConversationDocument>): Promise<IInstagramCommentConversationDocument>;
 }
backend/plugins/frontline_api/src/modules/integrations/instagram/db/models/Comment_conversations_reply.ts (1)

10-13: Consider stronger typing for selector parameter.

Same suggestion as for Comment_conversations.ts - using FilterQuery<IInstagramCommentConversationReplyDocument> would improve type safety.

backend/plugins/frontline_api/src/modules/integrations/instagram/types.ts (1)

9-11: Avoid using any type — define explicit types for better type safety.

Multiple properties use any (lines 9, 11, 22, 31, 37), which undermines TypeScript's benefits. The inline comments already acknowledge this. Consider defining proper types:

♻️ Suggested improvement
-      attachments?: Array<{
-        type: string;
-        payload?: any;
-      }>;
-      quick_reply?: any; // Consider defining a type here if you know its structure
+      attachments?: Array<{
+        type: 'image' | 'video' | 'audio' | 'file' | 'share' | 'story_mention';
+        payload?: {
+          url?: string;
+          sticker_id?: number;
+        };
+      }>;
+      quick_reply?: {
+        payload: string;
+      };
backend/plugins/frontline_api/src/modules/integrations/instagram/commonUtils.ts (5)

4-4: Remove unused import debugExternalRequests.

debugExternalRequests is imported but never used in this file.

Suggested fix
-import { debugBase, debugExternalRequests } from './debuggers';
+import { debugBase } from './debuggers';

11-35: Remove unused IRequestParams interface.

This interface is defined but never used in this file. If it's intended for future use, consider adding it when needed to avoid dead code.


101-101: Add type annotations for code and defaultValue parameters.

Per coding guidelines, TypeScript should be used with explicit types. The code and defaultValue parameters are implicitly typed as any.

Suggested fix
-export const getConfig = async (models: IModels, code, defaultValue?) => {
+export const getConfig = async (models: IModels, code: string, defaultValue?: string) => {

123-125: Consider using redis.del() for cache invalidation.

Setting the cache to an empty string works due to the falsy check in getConfigs, but using redis.del(CACHE_NAME) would be more explicit and conventional for cache invalidation.

Suggested fix
 export const resetConfigsCache = async () => {
-  await redis.set(CACHE_NAME, '');
+  await redis.del(CACHE_NAME);
 };

82-99: Consider adding TTL for cache expiration and explicit typing.

The Redis cache has no expiration, relying solely on manual invalidation via resetConfigsCache. Adding a TTL would provide automatic expiration if the cache invalidation is missed. Also, add explicit typing for configsMap based on the config model structure where config.value is a string.

Suggested improvements
 export const getConfigs = async (models: IModels) => {
   const configsCache = await redis.get(CACHE_NAME);

   if (configsCache && configsCache !== '{}') {
     return JSON.parse(configsCache);
   }

-  const configsMap = {};
+  const configsMap: Record<string, string> = {};
   const configs = await models.Configs.find({});

   for (const config of configs) {
     configsMap[config.code] = config.value;
   }

-  await redis.set(CACHE_NAME, JSON.stringify(configsMap));
+  await redis.set(CACHE_NAME, JSON.stringify(configsMap), 'EX', 3600); // 1 hour TTL

   return configsMap;
 };
backend/plugins/frontline_api/src/connectionResolvers.ts (2)

180-192: Inconsistent import path styles.

Some imports use absolute paths (@/integrations/instagram/...) while others use relative paths (./modules/integrations/instagram/...). Per coding guidelines, always use absolute paths.

♻️ Suggested fix: standardize to absolute paths
 import { IInstagramAccountModel, loadInstagramAccountClass } from '@/integrations/instagram/db/models/Accounts'
 import { IInstagramAccountDocument } from '@/integrations/instagram/@types/accounts';
 import { IInstagramIntegrationModel, loadInstagramIntegrationClass } from '@/integrations/instagram/db/models/Integrations'
 import { IInstagramIntegrationDocument } from '@/integrations/instagram/@types/integrations'
 import { IInstagramBotModel, loadInstagramBotClass } from '@/integrations/instagram/db/models/Bots'
-import { IInstagramBotDocument } from './modules/integrations/instagram/@types/bots';
-import { IInstagramCommentConversationReplyModel, loadInstagramCommentConversationReplyClass } from './modules/integrations/instagram/db/models/Comment_conversations_reply';
+import { IInstagramBotDocument } from '@/integrations/instagram/@types/bots';
+import { IInstagramCommentConversationReplyModel, loadInstagramCommentConversationReplyClass } from '@/integrations/instagram/db/models/Comment_conversations_reply';
 import { IInstagramCommentConversationReplyDocument } from '@/integrations/instagram/@types/comment_conversations_reply'
-import { IInstagramCommentConversationModel, loadInstagramCommentConversationClass  } from './modules/integrations/instagram/db/models/Comment_conversations';
+import { IInstagramCommentConversationModel, loadInstagramCommentConversationClass } from '@/integrations/instagram/db/models/Comment_conversations';
 import { IInstagramCommentConversationDocument } from '@/integrations/instagram/@types/comment_conversations';
-import { IInstagramConfigDocument } from './modules/integrations/instagram/@types/configs';
-import { IInstagramConfigModel, loadInstagramConfigClass } from './modules/integrations/instagram/db/models/Configs';
+import { IInstagramConfigDocument } from '@/integrations/instagram/@types/configs';
+import { IInstagramConfigModel, loadInstagramConfigClass } from '@/integrations/instagram/db/models/Configs';

216-222: Minor formatting inconsistency: extra spaces before colons.

🧹 Suggested fix
   //instagram
-  InstagramAccounts : IInstagramAccountModel;
+  InstagramAccounts: IInstagramAccountModel;
   InstagramIntegrations: IInstagramIntegrationModel;
   InstagramBots: IInstagramBotModel;
-  InstagramCommentConversationReply : IInstagramCommentConversationReplyModel;
-  InstagramCommentConversation : IInstagramCommentConversationModel;
-  InstagramConfig : IInstagramConfigModel;
+  InstagramCommentConversationReply: IInstagramCommentConversationReplyModel;
+  InstagramCommentConversation: IInstagramCommentConversationModel;
+  InstagramConfig: IInstagramConfigModel;
backend/plugins/frontline_api/src/modules/knowledgebase/graphql/resolvers/customResolvers/category.ts (1)

23-38: Duplicate author IDs not filtered.

Multiple articles may have the same createdBy author, resulting in duplicate User references in the returned array. Consider deduplicating.

♻️ Suggested fix
   async authors(category: ICategoryDocument, _args, { models }: IContext) {
     const articles = await models.Article.find(
       {
         categoryId: category._id,
         status: { $in: [PUBLISH_STATUSES.PUBLISH, PUBLISH_STATUSES.DRAFT] },
       },
       { createdBy: 1 }
     );

-    const authorIds = articles.map((article) => article.createdBy);
+    const authorIds = [...new Set(articles.map((article) => article.createdBy))];

-    return (authorIds || []).map((_id) => ({
+    return authorIds.map((_id) => ({
       __typename: 'User',
       _id,
     }));
   },
backend/plugins/frontline_api/src/modules/integrations/instagram/utils.ts (4)

139-141: Redundant try-catch block.

The catch block at lines 139-141 simply rethrows the error without transformation or logging. This adds no value and can be removed.

Proposed fix
       }
     }

     return null;
-  } catch (error) {
-    throw error;
-  }
+  }
 };

143-150: Missing type annotations for parameters.

The pageId and pageToken parameters lack TypeScript type annotations. Per coding guidelines, all code should use TypeScript with proper typing.

Proposed fix
 export const subscribePage = async (
-  pageId,
-  pageToken
+  pageId: string,
+  pageToken: string
 ): Promise<{ success: true } | any> => {

Apply similarly to unsubscribePage at lines 217-220.


240-242: Redundant try-catch block.

Same issue as getFacebookPageIdsForInsta - the catch block simply rethrows without adding value.


279-288: Unnecessary await on synchronous function.

getPageAccessTokenFromMap is a synchronous function that returns a string directly. The await on line 280 is unnecessary.

Proposed fix
   if (facebookPageTokensMap !== undefined) {
-    const token = await getPageAccessTokenFromMap(
+    const token = getPageAccessTokenFromMap(
       facebookPageId,
       facebookPageTokensMap
     );
backend/plugins/frontline_api/src/modules/integrations/instagram/db/definitions/integrations.ts (1)

4-22: Consider adding timestamps and indexing commonly queried fields.

A few observations:

  1. Missing timestamps: Unlike configSchema, this schema doesn't enable timestamps: true. Consider adding for consistency and audit trail.

  2. expiration as String: If this represents token expiration time, a Date type would enable proper comparison and TTL operations.

  3. Indexes: Fields like accountId, erxesApiId, and instagramPageId may benefit from indexes if frequently queried.

♻️ Suggested improvements
 export const integrationSchema = new Schema({
     _id: mongooseStringRandomId,
     kind: String,
-    accountId: String,
-    erxesApiId: String,
+    accountId: { type: String, index: true },
+    erxesApiId: { type: String, index: true },
     emailScope: String,
-    instagramPageId: String,
+    instagramPageId: { type: String, index: true },
     facebookPageId: String,
-  
     email: String,
-    expiration: String,
-  
-    facebookPageTokensMap:{
+    expiration: Date,
+    facebookPageTokensMap: {
       type: Object,
       default: {}
     },
     healthStatus: String,
     error: String
-  });
+  }, {
+    timestamps: true,
+  });
backend/plugins/frontline_api/src/modules/integrations/instagram/@types/configs.ts (2)

8-10: Inconsistent document typing pattern.

This file uses extends IInstagramConfig, Document while accounts.ts uses the modern HydratedDocument<T> pattern. For consistency across the Instagram types and better type inference with Mongoose 8.x, consider aligning to HydratedDocument.

♻️ Suggested refactor
-import { Document } from "mongoose";
+import { HydratedDocument } from "mongoose";

 export interface IInstagramConfig {
     code: string;
     value: any;
   }
-  
-  export interface IInstagramConfigDocument extends IInstagramConfig, Document {
-    _id: string;
-  }
+
+  export type IInstagramConfigDocument = HydratedDocument<IInstagramConfig>;

5-5: Consider using a stricter type than any for value.

Per coding guidelines favoring TypeScript best practices, value: any loses type safety. If the config value structure is known, consider using a more specific type or unknown to enforce type checking at usage sites.

backend/plugins/frontline_api/src/modules/integrations/instagram/db/definitions/accounts.ts (1)

4-5: Align schema export pattern with sibling definitions.

The file uses schemaWrapper() while configs.ts and integrations.ts export raw Schema instances. Consider standardizing the approach across all Instagram schema definitions.

backend/plugins/frontline_api/src/modules/integrations/instagram/db/models/Integrations.ts (1)

7-7: Add type annotation for selector parameter.

The selector parameter lacks a type annotation. Per coding guidelines, TypeScript should be used for all code.

Proposed fix
-    getIntegration(selector): Promise<IInstagramIntegrationDocument>;
+    getIntegration(selector: Record<string, unknown>): Promise<IInstagramIntegrationDocument>;
backend/plugins/frontline_api/src/modules/integrations/instagram/db/models/Accounts.ts (1)

6-8: Add type annotation for selector parameter.

The selector parameter in both the interface and implementation lacks a type annotation. Per coding guidelines, TypeScript should be used for all code.

Proposed fix
 export interface IInstagramAccountModel extends Model<IInstagramAccountDocument> {
-    getAccount(selector): Promise<IInstagramAccountDocument>;
+    getAccount(selector: Record<string, unknown>): Promise<IInstagramAccountDocument>;
   }
-      public static async getAccount(selector) {
+      public static async getAccount(selector: Record<string, unknown>) {
backend/plugins/frontline_api/src/modules/integrations/instagram/db/models/Configs.ts (1)

10-11: Add type annotations for configsMap parameter.

The configsMap parameter in both the interface and implementation lacks a type annotation. Per coding guidelines, TypeScript should be used for all code.

Proposed fix
-    updateConfigs(configsMap): Promise<void>;
+    updateConfigs(configsMap: Record<string, unknown>): Promise<void>;
-      public static async updateConfigs(configsMap) {
+      public static async updateConfigs(configsMap: Record<string, unknown>) {

Also applies to: 53-53

backend/plugins/frontline_api/src/modules/integrations/instagram/@types/bots.ts (2)

3-8: Consider exporting IPersistentMenus and review the _id type.

IPersistentMenus is not exported but may be needed by consumers that work with persistent menus. Also, _id: number is unusual for document identifiers—typically string or Mongoose's ObjectId is used. Verify this is intentional.

♻️ Suggested improvement
-interface IPersistentMenus {
-    _id: number;
+export interface IPersistentMenus {
+  _id: string;
   text: string;
   type: string;
   link?: string;
-  }
+}

9-25: Inconsistent indentation throughout the file.

The interfaces have extra leading spaces before their declarations. This should be cleaned up for consistency.

♻️ Suggested fix
-  export interface IBot {
-    name: string;
-    accountId: string;
-    uid: string;
-    pageId: string;
-    token: string;
-    status: string;
-    persistentMenus: IPersistentMenus[];
-    greetText?: string;
-    tag?: string;
-    isEnabledBackBtn?: boolean;
-    backButtonText?: string;
-  }
-  
-  export interface IInstagramBotDocument extends IBot, Document {
-    _id: string;
-  }
-  
+export interface IBot {
+  name: string;
+  accountId: string;
+  uid: string;
+  pageId: string;
+  token: string;
+  status: string;
+  persistentMenus: IPersistentMenus[];
+  greetText?: string;
+  tag?: string;
+  isEnabledBackBtn?: boolean;
+  backButtonText?: string;
+}
+
+export interface IInstagramBotDocument extends IBot, Document {
+  _id: string;
+}
backend/plugins/frontline_api/src/modules/integrations/instagram/db/models/Bots.ts (4)

4-10: Unused import getPageAccessTokenInstagram.

getPageAccessTokenInstagram is imported but never used in this file.

♻️ Remove unused import
 import {
   getPageAccessToken,
-  graphRequest,
-  getPageAccessTokenInstagram
+  graphRequest
 } from '@/integrations/instagram/utils';

12-33: Add type annotation for doc parameter.

The doc parameter is typed as any, which loses type safety. Consider using Partial<IBot> or a dedicated input type. As per coding guidelines, TypeScript should be used with proper typing.

♻️ Suggested improvement
-const validateDoc = async (models: IModels, doc: any, isUpdate?: boolean) => {
+const validateDoc = async (models: IModels, doc: Partial<IBot>, isUpdate?: boolean) => {

44-51: Add type annotation for _id parameter.

Missing type annotation on the _id parameter. Based on coding guidelines, use TypeScript properly.

♻️ Suggested fix
-    static async getBot(_id) {
+    static async getBot(_id: string) {

52-87: Redundant try-catch and missing type annotation.

  1. The doc parameter lacks a type annotation.
  2. Lines 55-57 catch an error and re-throw with error.message, which loses the stack trace and is redundant. The same pattern appears in lines 82-86.
♻️ Suggested improvement
-    public static async addBot(doc) {
-      try {
-        await validateDoc(models, doc);
-      } catch (error) {
-        throw new Error(error.message);
-      }
+    public static async addBot(doc: Partial<IBot>) {
+      await validateDoc(models, doc);
 
       const { accountId, pageId } = doc;
       // ... rest of the method
 
-      } catch (error) {
-        await models.InstagramBots.deleteOne({ _id: bot._id });
-
-        throw new Error(error.message);
-      }
+      } catch (error) {
+        await models.InstagramBots.deleteOne({ _id: bot._id });
+        throw error;
+      }
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5b2d99a and efe8ef3.

📒 Files selected for processing (34)
  • backend/plugins/frontline_api/src/apollo/resolvers/mutations.ts
  • backend/plugins/frontline_api/src/connectionResolvers.ts
  • backend/plugins/frontline_api/src/modules/integrations/facebook/db/definitions/comment_conversations_reply.ts
  • backend/plugins/frontline_api/src/modules/integrations/instagram/@types/accounts.ts
  • backend/plugins/frontline_api/src/modules/integrations/instagram/@types/bots.ts
  • backend/plugins/frontline_api/src/modules/integrations/instagram/@types/comment_conversations.ts
  • backend/plugins/frontline_api/src/modules/integrations/instagram/@types/comment_conversations_reply.ts
  • backend/plugins/frontline_api/src/modules/integrations/instagram/@types/configs.ts
  • backend/plugins/frontline_api/src/modules/integrations/instagram/@types/integrations.ts
  • backend/plugins/frontline_api/src/modules/integrations/instagram/commonUtils.ts
  • backend/plugins/frontline_api/src/modules/integrations/instagram/constants.ts
  • backend/plugins/frontline_api/src/modules/integrations/instagram/db/definitions/accounts.ts
  • backend/plugins/frontline_api/src/modules/integrations/instagram/db/definitions/bots.ts
  • backend/plugins/frontline_api/src/modules/integrations/instagram/db/definitions/comment_conversations.ts
  • backend/plugins/frontline_api/src/modules/integrations/instagram/db/definitions/comment_conversations_reply.ts
  • backend/plugins/frontline_api/src/modules/integrations/instagram/db/definitions/configs.ts
  • backend/plugins/frontline_api/src/modules/integrations/instagram/db/definitions/conversationMessages.ts
  • backend/plugins/frontline_api/src/modules/integrations/instagram/db/definitions/conversations.ts
  • backend/plugins/frontline_api/src/modules/integrations/instagram/db/definitions/customers.ts
  • backend/plugins/frontline_api/src/modules/integrations/instagram/db/definitions/integrations.ts
  • backend/plugins/frontline_api/src/modules/integrations/instagram/db/definitions/logs.ts
  • backend/plugins/frontline_api/src/modules/integrations/instagram/db/definitions/postConversations.ts
  • backend/plugins/frontline_api/src/modules/integrations/instagram/db/models/Accounts.ts
  • backend/plugins/frontline_api/src/modules/integrations/instagram/db/models/Bots.ts
  • backend/plugins/frontline_api/src/modules/integrations/instagram/db/models/Comment_conversations.ts
  • backend/plugins/frontline_api/src/modules/integrations/instagram/db/models/Comment_conversations_reply.ts
  • backend/plugins/frontline_api/src/modules/integrations/instagram/db/models/Configs.ts
  • backend/plugins/frontline_api/src/modules/integrations/instagram/db/models/Integrations.ts
  • backend/plugins/frontline_api/src/modules/integrations/instagram/debuggers.ts
  • backend/plugins/frontline_api/src/modules/integrations/instagram/types.ts
  • backend/plugins/frontline_api/src/modules/integrations/instagram/utils.ts
  • backend/plugins/frontline_api/src/modules/knowledgebase/graphql/resolvers/customResolvers/category.ts
  • backend/plugins/frontline_api/src/modules/knowledgebase/graphql/resolvers/customResolvers/topic.ts
  • backend/plugins/frontline_api/src/modules/knowledgebase/graphql/resolvers/queries/knowledgeBaseQueries.ts
✅ Files skipped from review due to trivial changes (1)
  • backend/plugins/frontline_api/src/modules/integrations/facebook/db/definitions/comment_conversations_reply.ts
🚧 Files skipped from review as they are similar to previous changes (5)
  • backend/plugins/frontline_api/src/modules/integrations/instagram/@types/comment_conversations.ts
  • backend/plugins/frontline_api/src/apollo/resolvers/mutations.ts
  • backend/plugins/frontline_api/src/modules/knowledgebase/graphql/resolvers/customResolvers/topic.ts
  • backend/plugins/frontline_api/src/modules/knowledgebase/graphql/resolvers/queries/knowledgeBaseQueries.ts
  • backend/plugins/frontline_api/src/modules/integrations/instagram/@types/comment_conversations_reply.ts
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursorrules)

**/*.{ts,tsx}: Write concise, technical TypeScript code with accurate examples
Use functional and declarative programming patterns; avoid classes
Prefer iteration and modularization over code duplication
Use descriptive variable names with auxiliary verbs (e.g., isLoading, hasError)
Structure files: exported component, utils, contexts, hooks, types
Avoid console logs
Always use absolute paths when importing
Favor named exports for components
Use TypeScript for all code; prefer interfaces over types
Avoid enums; use maps instead
Use functional components with TypeScript interfaces
Use the 'function' keyword for pure functions
Avoid unnecessary curly braces in conditionals; use concise syntax for simple statements

Files:

  • backend/plugins/frontline_api/src/modules/integrations/instagram/db/definitions/conversations.ts
  • backend/plugins/frontline_api/src/modules/integrations/instagram/db/definitions/configs.ts
  • backend/plugins/frontline_api/src/modules/integrations/instagram/@types/configs.ts
  • backend/plugins/frontline_api/src/modules/integrations/instagram/db/definitions/comment_conversations.ts
  • backend/plugins/frontline_api/src/modules/integrations/instagram/db/definitions/comment_conversations_reply.ts
  • backend/plugins/frontline_api/src/modules/integrations/instagram/db/definitions/integrations.ts
  • backend/plugins/frontline_api/src/modules/integrations/instagram/types.ts
  • backend/plugins/frontline_api/src/modules/integrations/instagram/db/definitions/accounts.ts
  • backend/plugins/frontline_api/src/modules/integrations/instagram/db/definitions/postConversations.ts
  • backend/plugins/frontline_api/src/modules/integrations/instagram/db/definitions/bots.ts
  • backend/plugins/frontline_api/src/modules/integrations/instagram/@types/accounts.ts
  • backend/plugins/frontline_api/src/modules/integrations/instagram/constants.ts
  • backend/plugins/frontline_api/src/modules/integrations/instagram/db/definitions/logs.ts
  • backend/plugins/frontline_api/src/modules/integrations/instagram/@types/integrations.ts
  • backend/plugins/frontline_api/src/modules/integrations/instagram/db/models/Comment_conversations.ts
  • backend/plugins/frontline_api/src/modules/integrations/instagram/db/models/Comment_conversations_reply.ts
  • backend/plugins/frontline_api/src/modules/integrations/instagram/db/definitions/conversationMessages.ts
  • backend/plugins/frontline_api/src/modules/knowledgebase/graphql/resolvers/customResolvers/category.ts
  • backend/plugins/frontline_api/src/modules/integrations/instagram/commonUtils.ts
  • backend/plugins/frontline_api/src/modules/integrations/instagram/db/models/Configs.ts
  • backend/plugins/frontline_api/src/modules/integrations/instagram/db/models/Accounts.ts
  • backend/plugins/frontline_api/src/modules/integrations/instagram/utils.ts
  • backend/plugins/frontline_api/src/modules/integrations/instagram/db/models/Bots.ts
  • backend/plugins/frontline_api/src/modules/integrations/instagram/@types/bots.ts
  • backend/plugins/frontline_api/src/modules/integrations/instagram/db/models/Integrations.ts
  • backend/plugins/frontline_api/src/modules/integrations/instagram/db/definitions/customers.ts
  • backend/plugins/frontline_api/src/modules/integrations/instagram/debuggers.ts
  • backend/plugins/frontline_api/src/connectionResolvers.ts
🧬 Code graph analysis (13)
backend/plugins/frontline_api/src/modules/integrations/instagram/@types/configs.ts (1)
frontend/libs/ui-modules/src/modules/documents/components/DocumentsInline.tsx (1)
  • Document (14-17)
backend/plugins/frontline_api/src/modules/integrations/instagram/db/definitions/comment_conversations_reply.ts (1)
backend/plugins/frontline_api/src/modules/integrations/facebook/db/definitions/comment_conversations_reply.ts (1)
  • commentConversationReplySchema (5-19)
backend/plugins/frontline_api/src/modules/integrations/instagram/db/definitions/logs.ts (1)
backend/plugins/frontline_api/src/modules/integrations/instagram/constants.ts (1)
  • LOG_TYPES (1-6)
backend/plugins/frontline_api/src/modules/integrations/instagram/@types/integrations.ts (1)
frontend/libs/ui-modules/src/modules/documents/components/DocumentsInline.tsx (1)
  • Document (14-17)
backend/plugins/frontline_api/src/modules/integrations/instagram/db/models/Comment_conversations.ts (3)
backend/plugins/frontline_api/src/modules/integrations/instagram/@types/comment_conversations.ts (1)
  • IInstagramCommentConversationDocument (17-21)
backend/plugins/frontline_api/src/connectionResolvers.ts (1)
  • IModels (194-258)
backend/plugins/frontline_api/src/modules/integrations/instagram/db/definitions/comment_conversations.ts (1)
  • commentConversationSchema (5-20)
backend/plugins/frontline_api/src/modules/integrations/instagram/db/models/Comment_conversations_reply.ts (3)
backend/plugins/frontline_api/src/modules/integrations/instagram/@types/comment_conversations_reply.ts (1)
  • IInstagramCommentConversationReplyDocument (20-22)
backend/plugins/frontline_api/src/connectionResolvers.ts (1)
  • IModels (194-258)
backend/plugins/frontline_api/src/modules/integrations/instagram/db/definitions/comment_conversations_reply.ts (1)
  • commentConversationReplySchema (5-21)
backend/plugins/frontline_api/src/modules/knowledgebase/graphql/resolvers/customResolvers/category.ts (2)
backend/plugins/frontline_api/src/connectionResolvers.ts (1)
  • IContext (260-264)
backend/plugins/frontline_api/src/modules/knowledgebase/db/definitions/constant.ts (1)
  • PUBLISH_STATUSES (2-7)
backend/plugins/frontline_api/src/modules/integrations/instagram/commonUtils.ts (4)
scripts/start-ui-dev.js (1)
  • process (4-4)
backend/plugins/frontline_api/src/modules/integrations/instagram/debuggers.ts (1)
  • debugBase (6-6)
frontend/libs/erxes-ui/src/utils/config/index.ts (1)
  • NODE_ENV (63-63)
backend/plugins/frontline_api/src/connectionResolvers.ts (1)
  • IModels (194-258)
backend/plugins/frontline_api/src/modules/integrations/instagram/db/models/Configs.ts (3)
backend/plugins/frontline_api/src/modules/integrations/instagram/@types/configs.ts (2)
  • IInstagramConfigDocument (8-10)
  • IInstagramConfig (3-6)
backend/plugins/frontline_api/src/connectionResolvers.ts (1)
  • IModels (194-258)
backend/plugins/frontline_api/src/modules/integrations/instagram/db/definitions/configs.ts (1)
  • configSchema (4-13)
backend/plugins/frontline_api/src/modules/integrations/instagram/db/models/Accounts.ts (3)
backend/plugins/frontline_api/src/modules/integrations/instagram/@types/accounts.ts (1)
  • IInstagramAccountDocument (15-15)
backend/plugins/frontline_api/src/connectionResolvers.ts (1)
  • IModels (194-258)
backend/plugins/frontline_api/src/modules/integrations/instagram/db/definitions/accounts.ts (1)
  • accountSchema (4-26)
backend/plugins/frontline_api/src/modules/integrations/instagram/@types/bots.ts (1)
frontend/libs/ui-modules/src/modules/documents/components/DocumentsInline.tsx (1)
  • Document (14-17)
backend/plugins/frontline_api/src/modules/integrations/instagram/db/models/Integrations.ts (4)
backend/plugins/frontline_api/src/modules/integrations/instagram/@types/integrations.ts (1)
  • IInstagramIntegrationDocument (17-17)
backend/plugins/frontline_api/src/connectionResolvers.ts (1)
  • IModels (194-258)
backend/plugins/frontline_api/src/modules/inbox/graphql/resolvers/customResolvers/conversation.ts (1)
  • integration (26-34)
backend/plugins/frontline_api/src/modules/integrations/instagram/db/definitions/integrations.ts (1)
  • integrationSchema (4-22)
backend/plugins/frontline_api/src/connectionResolvers.ts (9)
backend/plugins/frontline_api/src/modules/integrations/instagram/db/models/Accounts.ts (2)
  • IInstagramAccountModel (6-8)
  • loadInstagramAccountClass (10-26)
backend/plugins/frontline_api/src/modules/integrations/instagram/db/models/Integrations.ts (2)
  • IInstagramIntegrationModel (6-8)
  • loadInstagramIntegrationClass (10-27)
backend/plugins/frontline_api/src/modules/integrations/instagram/db/models/Bots.ts (2)
  • IInstagramBotModel (35-40)
  • loadInstagramBotClass (42-275)
backend/plugins/frontline_api/src/modules/integrations/instagram/db/models/Comment_conversations_reply.ts (2)
  • IInstagramCommentConversationReplyModel (10-13)
  • loadInstagramCommentConversationReplyClass (15-31)
backend/plugins/frontline_api/src/modules/integrations/instagram/db/models/Comment_conversations.ts (2)
  • IInstagramCommentConversationModel (9-12)
  • loadInstagramCommentConversationClass (14-30)
backend/plugins/frontline_api/src/modules/integrations/instagram/db/models/Configs.ts (2)
  • IInstagramConfigModel (8-12)
  • loadInstagramConfigClass (14-72)
backend/plugins/frontline_api/src/modules/knowledgebase/db/models/Article.ts (2)
  • IArticleModel (15-32)
  • loadArticleClass (34-132)
backend/plugins/frontline_api/src/modules/knowledgebase/db/models/Category.ts (2)
  • ICategoryModel (11-23)
  • loadCategoryClass (25-111)
backend/plugins/frontline_api/src/modules/knowledgebase/db/models/Topic.ts (2)
  • ITopicModel (8-17)
  • loadTopicClass (19-89)
⏰ 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). (2)
  • GitHub Check: frontline_api-ci
  • GitHub Check: Analyze (javascript-typescript)

Comment on lines 3 to 13
export interface IInstagramAccount {
kind: string;
token: string;
username?: string;
email: string;
tokenSecret?: string;
expireDate?: string;
scope?: string;
name: string;
uid: string;
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, let's find and examine the schema definition file
find backend/plugins/frontline_api/src/modules/integrations/instagram -name "accounts.ts" -type f

Repository: erxes/erxes

Length of output: 230


🏁 Script executed:

# Examine the schema file (db/definitions/accounts.ts)
cat -n backend/plugins/frontline_api/src/modules/integrations/instagram/db/definitions/accounts.ts

Repository: erxes/erxes

Length of output: 763


🏁 Script executed:

# Examine the type definition file (@types/accounts.ts)
cat -n backend/plugins/frontline_api/src/modules/integrations/instagram/@types/accounts.ts

Repository: erxes/erxes

Length of output: 514


Type definition doesn't match the schema.

The interface IInstagramAccount includes username (optional) and email (required) fields that are not defined in accountSchema. The schema defines kind, token, tokenSecret, scope, expireDate, name, and uid, but lacks username and email entirely.

This mismatch causes runtime issues—specifically, email is required in the type but absent from the schema, meaning persisted documents will lack this property despite the type expecting it.

🤖 Prompt for AI Agents
In
@backend/plugins/frontline_api/src/modules/integrations/instagram/@types/accounts.ts
around lines 3 - 13, The TypeScript interface IInstagramAccount is out of sync
with the persistence schema (accountSchema) — it declares username? and a
required email that the schema does not define; update either the interface or
the schema so they match: if email and username should be stored, add those
fields to accountSchema with correct types and optional/required flags and
update any validation; otherwise remove username and email from
IInstagramAccount (or make email optional) to reflect the schema. Locate
IInstagramAccount in accounts.ts and the corresponding accountSchema definition
and make the change consistently across code that reads/writes Instagram
accounts.

Comment on lines 11 to 22
tokenSecret: {
type: String,
optional: true
},
scope: {
type: String,
optional: true
},
expireDate: {
type: String,
optional: true
},
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

optional: true is not a valid Mongoose schema option.

Mongoose doesn't recognize optional as a schema type option. Fields are optional by default in Mongoose; use required: true to make them mandatory. The current optional: true declarations have no effect and may cause confusion.

🐛 Proposed fix
     tokenSecret: {
-      type: String,
-      optional: true
+      type: String
     },
     scope: {
-      type: String,
-      optional: true
+      type: String
     },
     expireDate: {
-      type: String,
-      optional: true
+      type: String
     },
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
tokenSecret: {
type: String,
optional: true
},
scope: {
type: String,
optional: true
},
expireDate: {
type: String,
optional: true
},
tokenSecret: {
type: String
},
scope: {
type: String
},
expireDate: {
type: String
},
🤖 Prompt for AI Agents
In
@backend/plugins/frontline_api/src/modules/integrations/instagram/db/definitions/accounts.ts
around lines 11 - 22, The schema fields tokenSecret, scope, and expireDate are
using an invalid Mongoose option `optional: true`; remove the `optional` entries
(fields are optional by default) or replace with `required: true` where you
intend a mandatory field; update the object definitions for tokenSecret, scope,
and expireDate in the accounts schema (remove `optional: true` from each or
switch to `required: true` as appropriate) so the schema uses valid Mongoose
options.

persistentMenus: { type: [persistentMenuSchema] },
greetText: { type: String, optional: true },
tag: { type: String, optional: true },
createdAt: { type: Date, default: Date.now() },
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Date.now() evaluated at schema definition time, not document creation.

Using Date.now() (with parentheses) executes immediately when the schema is defined, so all documents will share the same timestamp from server startup. Pass the function reference instead.

Proposed fix
-    createdAt: { type: Date, default: Date.now() },
+    createdAt: { type: Date, default: Date.now },
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
createdAt: { type: Date, default: Date.now() },
createdAt: { type: Date, default: Date.now },
🤖 Prompt for AI Agents
In
@backend/plugins/frontline_api/src/modules/integrations/instagram/db/definitions/bots.ts
at line 23, The createdAt field in the schema uses Date.now() which is evaluated
at schema-definition time; change the default to the function reference Date.now
(no parentheses) in the bots schema definition (the createdAt property in this
file) so a fresh timestamp is generated when each document is created.

Comment on lines 5 to 19
export const commentConversationSchema = schemaWrapper(
new Schema({
_id: mongooseStringRandomId,
mid: { type: String, label: 'comment message id' },
postId: { type: String },
comment_id: { type: String },
recipientId: { type: String },
senderId: { type: String },
content: String,
erxesApiId: String,
customerId: { type: String, optional: true },
createdAt: { type: Date, default: Date.now, label: 'Created At' },
updatedAt: { type: Date, index: true, label: 'Updated At' },
attachments: [attachmentSchema],
})
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# Check if isResolved is used with InstagramCommentConversation anywhere
rg -n "isResolved" --type=ts -C2 -g '**/instagram/**'

Repository: erxes/erxes

Length of output: 1899


🏁 Script executed:

# Find the types/interface file for comment conversations
fd "comment_conversations" --type f -g '**/@types/**' -o -g '**/types/**'

Repository: erxes/erxes

Length of output: 171


🏁 Script executed:

# Look at the directory structure to understand the layout
ls -la backend/plugins/frontline_api/src/modules/integrations/instagram/db/definitions/ 2>/dev/null || find . -path "*instagram/db/definitions*" -type d

Repository: erxes/erxes

Length of output: 891


🏁 Script executed:

# Read the interface file to see the full IInstagramCommentConversationDocument
cat -n backend/plugins/frontline_api/src/modules/integrations/instagram/@types/comment_conversations.ts

Repository: erxes/erxes

Length of output: 629


🏁 Script executed:

# Read the schema file to confirm it's missing the isResolved field
cat -n backend/plugins/frontline_api/src/modules/integrations/instagram/db/definitions/comment_conversations.ts

Repository: erxes/erxes

Length of output: 944


🏁 Script executed:

# Check the reply schema for comparison
cat -n backend/plugins/frontline_api/src/modules/integrations/instagram/db/definitions/comment_conversations_reply.ts

Repository: erxes/erxes

Length of output: 1032


Add the missing isResolved field to the schema.

The IInstagramCommentConversationDocument interface includes isResolved: any (line 20), but the schema definition doesn't include it. The commentConversationReplySchema includes isResolved: { type: Boolean, default: false } for consistency. Add this field to the schema to match the interface.

Schema comparison

Missing from commentConversationSchema:

isResolved: { type: Boolean, default: false }

Present in commentConversationReplySchema (line 19):

isResolved: { type: Boolean, default: false }
🤖 Prompt for AI Agents
In
@backend/plugins/frontline_api/src/modules/integrations/instagram/db/definitions/comment_conversations.ts
around lines 5 - 19, The commentConversationSchema is missing the isResolved
field declared on IInstagramCommentConversationDocument; add isResolved to
commentConversationSchema with type Boolean and default: false (matching
commentConversationReplySchema) so the schema and interface stay consistent and
new conversations default to unresolved.

Comment on lines 89 to 127
public static async repair(_id) {
const bot = await this.getBot(_id);

const account = await models.InstagramAccounts.findOne({ _id: bot.accountId });

if (!account) {
const relatedAccount = await models.InstagramAccounts.findOne({ uid: bot.uid });

if (!relatedAccount) {
throw new Error("Not found account");
}

const pageAccessToken = await getPageAccessToken(
bot.pageId,
relatedAccount.token
);

if (bot.token !== pageAccessToken) {
bot.token = pageAccessToken;
}

bot.accountId = relatedAccount._id.toString();
}

try {
await this.connectBotPageMessenger({
botId: bot._id,
pageAccessToken: bot.token,
persistentMenus: bot.persistentMenus,
greetText: bot.greetText,
isEnabledBackBtn: bot?.isEnabledBackBtn,
backButtonText: bot?.backButtonText
});
} catch (err) {
throw new Error(err.message);
}

return { status: "success" };
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Modified bot properties are not persisted to the database.

The repair method updates bot.token (line 107) and bot.accountId (line 110), but these changes are never saved to the database. The method returns success without persisting the repairs.

🐛 Proposed fix
         bot.accountId = relatedAccount._id.toString();
       }

       try {
         await this.connectBotPageMessenger({
           botId: bot._id,
           pageAccessToken: bot.token,
           persistentMenus: bot.persistentMenus,
           greetText: bot.greetText,
           isEnabledBackBtn: bot?.isEnabledBackBtn,
           backButtonText: bot?.backButtonText
         });
       } catch (err) {
         throw new Error(err.message);
       }

+      await bot.save();
       return { status: "success" };
     }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
public static async repair(_id) {
const bot = await this.getBot(_id);
const account = await models.InstagramAccounts.findOne({ _id: bot.accountId });
if (!account) {
const relatedAccount = await models.InstagramAccounts.findOne({ uid: bot.uid });
if (!relatedAccount) {
throw new Error("Not found account");
}
const pageAccessToken = await getPageAccessToken(
bot.pageId,
relatedAccount.token
);
if (bot.token !== pageAccessToken) {
bot.token = pageAccessToken;
}
bot.accountId = relatedAccount._id.toString();
}
try {
await this.connectBotPageMessenger({
botId: bot._id,
pageAccessToken: bot.token,
persistentMenus: bot.persistentMenus,
greetText: bot.greetText,
isEnabledBackBtn: bot?.isEnabledBackBtn,
backButtonText: bot?.backButtonText
});
} catch (err) {
throw new Error(err.message);
}
return { status: "success" };
}
public static async repair(_id) {
const bot = await this.getBot(_id);
const account = await models.InstagramAccounts.findOne({ _id: bot.accountId });
if (!account) {
const relatedAccount = await models.InstagramAccounts.findOne({ uid: bot.uid });
if (!relatedAccount) {
throw new Error("Not found account");
}
const pageAccessToken = await getPageAccessToken(
bot.pageId,
relatedAccount.token
);
if (bot.token !== pageAccessToken) {
bot.token = pageAccessToken;
}
bot.accountId = relatedAccount._id.toString();
}
try {
await this.connectBotPageMessenger({
botId: bot._id,
pageAccessToken: bot.token,
persistentMenus: bot.persistentMenus,
greetText: bot.greetText,
isEnabledBackBtn: bot?.isEnabledBackBtn,
backButtonText: bot?.backButtonText
});
} catch (err) {
throw new Error(err.message);
}
await bot.save();
return { status: "success" };
}
🤖 Prompt for AI Agents
In
@backend/plugins/frontline_api/src/modules/integrations/instagram/db/models/Bots.ts
around lines 89 - 127, The repair method mutates bot.token and bot.accountId but
never persists them; after updating those fields (in the branch that finds
relatedAccount) call and await a save/update on the bot record (e.g., await
bot.save() or models.Bots.updateOne({ _id: bot._id }, { token: bot.token,
accountId: bot.accountId })) before calling connectBotPageMessenger so the
repaired values are stored; also propagate/handle any save errors consistently
with the existing try/catch around connectBotPageMessenger.

Comment on lines 24 to 34
export const debugRequest = (debugInstance, req) =>
debugInstance(`
Receiving ${req.path} request from ${req.headers.origin}
body: ${JSON.stringify(req.body || {})}
queryParams: ${JSON.stringify(req.query)}
`);

export const debugResponse = (debugInstance, req, data = 'success') =>
debugInstance(
`Responding ${req.path} request to ${req.headers.origin} with ${data}`
);
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Add TypeScript types to function parameters.

Both debugRequest and debugResponse are missing type annotations for their parameters. Per coding guidelines, all code should use TypeScript. Additionally, req.headers.origin may be undefined for same-origin or non-browser requests, which could produce misleading log output.

Suggested fix with types
-export const debugRequest = (debugInstance, req) =>
+import type { Request } from 'express';
+import type { Debugger } from 'debug';
+
+export const debugRequest = (debugInstance: Debugger, req: Request) =>
   debugInstance(`
-        Receiving ${req.path} request from ${req.headers.origin}
+        Receiving ${req.path} request from ${req.headers.origin ?? 'unknown'}
         body: ${JSON.stringify(req.body || {})}
         queryParams: ${JSON.stringify(req.query)}
       `);

-export const debugResponse = (debugInstance, req, data = 'success') =>
+export const debugResponse = (debugInstance: Debugger, req: Request, data: string = 'success') =>
   debugInstance(
-    `Responding ${req.path} request to ${req.headers.origin} with ${data}`
+    `Responding ${req.path} request to ${req.headers.origin ?? 'unknown'} with ${data}`
   );
🤖 Prompt for AI Agents
In
@backend/plugins/frontline_api/src/modules/integrations/instagram/debuggers.ts
around lines 24 - 34, Add TypeScript types to the debug functions: annotate
debugRequest and debugResponse parameters so debugInstance is typed as a (msg:
string) => void and req is typed as Express's Request (import Request from
'express'); give data in debugResponse a specific type (e.g., string | unknown)
and a default of 'success'. Also guard against undefined origin by resolving a
safe origin string (e.g., const origin = req.headers.origin ?? req.get('host')
?? 'unknown') and use that in the log messages so logs never show "undefined".
Ensure the functions debugRequest and debugResponse signatures reflect these
types and import Request where needed.

Comment on lines 27 to 38
postback: {
title: string;
mid: string;
payload: string;
quick_reply?: any; // Same as above, consider typing it more specifically
};
comments: {
title: string;
mid: string;
payload: string;
quick_reply?: any;
};
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

postback and comments should likely be optional properties.

In Instagram webhooks, messages can be of different types — not every message will have both postback and comments data. Marking these as required could cause issues when processing messages that don't include them.

Additionally, postback and comments share an identical structure. Consider extracting a shared interface to reduce duplication.

🔧 Suggested fix
+interface IWebhookPayload {
+  title: string;
+  mid: string;
+  payload: string;
+  quick_reply?: {
+    payload: string;
+  };
+}
+
 export interface IMessageData {
   // ... other fields
-  postback: {
-    title: string;
-    mid: string;
-    payload: string;
-    quick_reply?: any;
-  };
-  comments: {
-    title: string;
-    mid: string;
-    payload: string;
-    quick_reply?: any;
-  };
+  postback?: IWebhookPayload;
+  comments?: IWebhookPayload;
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
postback: {
title: string;
mid: string;
payload: string;
quick_reply?: any; // Same as above, consider typing it more specifically
};
comments: {
title: string;
mid: string;
payload: string;
quick_reply?: any;
};
interface IWebhookPayload {
title: string;
mid: string;
payload: string;
quick_reply?: {
payload: string;
};
}
export interface IMessageData {
// ... other fields
postback?: IWebhookPayload;
comments?: IWebhookPayload;
}
🤖 Prompt for AI Agents
In @backend/plugins/frontline_api/src/modules/integrations/instagram/types.ts
around lines 27 - 38, postback and comments are declared as required
identical-structured objects but they should be optional and deduplicated;
define a shared interface (e.g., InstagramMessageDetail or
SharedInstagramPayload) capturing { title: string; mid: string; payload: string;
quick_reply?: any } then change the types for postback and comments to use this
interface and mark them optional (postback?: InstagramMessageDetail; comments?:
InstagramMessageDetail); update any imports/usages of postback/comments
accordingly.

Comment on lines 9 to 35
export const graphRequest = {
base(method: string, path?: any, accessToken?: any, ...otherParams) {
// set access token
graph.setAccessToken(accessToken);
graph.setVersion("19.0");

return new Promise((resolve, reject) => {
graph[method](path, ...otherParams, (error, response) => {
if (error) {
return reject(error);
}
return resolve(response);
});
});
},
get(...args): any {
return this.base("get", ...args);
},

post(...args): any {
return this.base("post", ...args);
},

delete(...args): any {
return this.base("del", ...args);
}
};
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🌐 Web query:

Facebook Graph API version 19.0 support January 2026 current versions

💡 Result:

Short answer: Graph API v19.0 is no longer supported as of January 13, 2026 — Meta announced deprecation to begin on February 4, 2025, and downstream vendors and SDKs list v19.0 as deprecated/removed. Migrate to a current Graph API version (v21+/v22+ depending on your needs). Sources: [1][2][3].

Sources

  • Announcement / coverage noting v19.0 release and Groups API changes. [1]
  • Vendor/SDK notices stating v19.0 deprecation commencement Feb 4, 2025. [2][3]

References

  1. Meta / coverage of Graph API v19.0 release (introducing v19.0).
  2. CData / Datavirtuality notices referencing deprecation (deprecation commence Feb 4, 2025).
  3. Multiple SDK/connector changelogs and vendor posts confirming upgrade paths and deprecation timeline.

🏁 Script executed:

# Examine the full file to understand context and typing patterns
head -100 backend/plugins/frontline_api/src/modules/integrations/instagram/utils.ts

Repository: erxes/erxes

Length of output: 2939


🏁 Script executed:

# Check if version is referenced elsewhere or if there's version management
rg "19\.0|setVersion|graph\." backend/plugins/frontline_api/src/modules/integrations/instagram/utils.ts -A 2

Repository: erxes/erxes

Length of output: 170


🏁 Script executed:

# Look for TypeScript configuration and interface definitions in the file
grep -n "interface\|type\|import" backend/plugins/frontline_api/src/modules/integrations/instagram/utils.ts | head -20

Repository: erxes/erxes

Length of output: 708


Migrate Graph API version from deprecated v19.0 to a supported version (v21+ or v22+).

Graph API v19.0 is deprecated and no longer supported as of January 2026. Meta discontinued support starting February 4, 2025. Update graph.setVersion("19.0") to a current version. Additionally, the base method uses any types for parameters and return values; add proper TypeScript interfaces for type safety (e.g., method: 'get' | 'post' | 'del', typed response objects).

🤖 Prompt for AI Agents
In @backend/plugins/frontline_api/src/modules/integrations/instagram/utils.ts
around lines 9 - 35, Update the hard-coded deprecated API version in
graphRequest.base by replacing graph.setVersion("19.0") with a supported version
(e.g., graph.setVersion("22.0") or "21.0") and ensure all calls use that
version; also strengthen types by changing base signature to accept method:
'get' | 'post' | 'del', typed path/accessToken parameters, and a typed Promise
return (replace all any usages in graphRequest.base and the get/post/delete
wrappers with appropriate interfaces for request params and response shape) so
graphRequest.get/post/delete return a correctly typed response.

Comment on lines 304 to 425
export const sendReply = async (
models: IModels,
url: string,
data: any,
integrationId: string
) => {
const integration = await models.InstagramIntegrations.findOne({
erxesApiId: integrationId
});
if (!integration) {
throw new Error("Integration not found");
}
const { facebookPageTokensMap = {}, facebookPageId } = integration;

let pageAccessToken: string | undefined;

try {
if (!facebookPageId) {
throw new Error("Facebook page ID is not defined.");
}

pageAccessToken = getPageAccessTokenFromMap(
facebookPageId,
facebookPageTokensMap
);

if (!pageAccessToken) {
throw new Error("Page access token not found.");
}

// Continue processing with `pageAccessToken`
} catch (e) {
debugError(
`Error occurred while trying to get page access token: ${e.message}`
);
return e;
}

try {
const response = await graphRequest.post(`${url}`, pageAccessToken, {
...data
});
debugInstagram(
`Successfully sent data to instagram ${JSON.stringify(data)}`
);
return response;
} catch (e) {
debugError(
`Error ocurred while trying to send post request to instagram ${
e.message
} data: ${JSON.stringify(data)}`
);

throw new Error(e.message);
}
};

export const sendReplyComment = async (
models: IModels,
url: string,
data: any,
integrationId: string
) => {
const integration = await models.InstagramIntegrations.findOne({
erxesApiId: integrationId
});
if (!integration) {
throw new Error("Integration not found");
}
const { facebookPageTokensMap = {}, facebookPageId } = integration;

let pageAccessToken: string | undefined;

try {
if (!facebookPageId) {
throw new Error("Facebook page ID is not defined.");
}

pageAccessToken = getPageAccessTokenFromMap(
facebookPageId,
facebookPageTokensMap
);

if (!pageAccessToken) {
throw new Error("Page access token not found.");
}

// Continue processing with `pageAccessToken`
} catch (e) {
debugError(
`Error occurred while trying to get page access token: ${e.message}`
);
return e;
}
const user = data.senderId;
const nameResponse = await graphRequest.get(
`/${user}?fields=name,username&access_token=${pageAccessToken}`
);
const name = nameResponse.username || nameResponse.name;
const messageData = {
message: `@${name} ${data.message}`, // Insert the user's name dynamically into the messa
attachment_url: data.attachmentUrl // Include the attachment URL
};

try {
const response = await graphRequest.post(`${url}`, pageAccessToken, {
...messageData
});
debugInstagram(
`Successfully sent data to instagram ${JSON.stringify(data)}`
);
return response;
} catch (e) {
debugError(
`Error ocurred while trying to send post request to facebook ${
e.message
} data: ${JSON.stringify(data)}`
);

throw new Error(e.message);
}
};
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Significant code duplication and inconsistent error handling.

sendReply and sendReplyComment share ~80% identical code for integration lookup and token retrieval. This violates the DRY principle. Consider extracting the common logic into a helper function.

Additionally, lines 339 and 396 return the error object instead of throwing, which is inconsistent with the error handling elsewhere in these functions and makes the API unpredictable for callers.

Line 418 incorrectly references "facebook" instead of "instagram".

Proposed refactor

Extract common logic:

const getIntegrationPageToken = async (
  models: IModels,
  integrationId: string
): Promise<{ integration: any; pageAccessToken: string }> => {
  const integration = await models.InstagramIntegrations.findOne({
    erxesApiId: integrationId
  });
  if (!integration) {
    throw new Error("Integration not found");
  }
  const { facebookPageTokensMap = {}, facebookPageId } = integration;

  if (!facebookPageId) {
    throw new Error("Facebook page ID is not defined.");
  }

  const pageAccessToken = getPageAccessTokenFromMap(
    facebookPageId,
    facebookPageTokensMap
  );

  if (!pageAccessToken) {
    throw new Error("Page access token not found.");
  }

  return { integration, pageAccessToken };
};

Then refactor both functions to use this helper and fix the error return:

-  } catch (e) {
-    debugError(
-      `Error occurred while trying to get page access token: ${e.message}`
-    );
-    return e;
-  }
+  } catch (e) {
+    debugError(
+      `Error occurred while trying to get page access token: ${e.message}`
+    );
+    throw e;
+  }

Fix the typo at line 418:

-      `Error ocurred while trying to send post request to facebook ${
+      `Error occurred while trying to send post request to instagram ${
🤖 Prompt for AI Agents
In @backend/plugins/frontline_api/src/modules/integrations/instagram/utils.ts
around lines 304 - 425, Extract the shared integration lookup and token
retrieval into a helper (e.g., getIntegrationPageToken(models, integrationId)
that returns { integration, pageAccessToken }) and update sendReply and
sendReplyComment to call that helper instead of duplicating the logic; replace
the try/catch blocks that currently return the caught error (e.g., the catch
branches in sendReply and sendReplyComment) with thrown Errors so callers
receive exceptions consistently; and fix the log message in sendReplyComment
that incorrectly says "facebook" to "instagram" (the debugError/debugInstagram
call that mentions facebook). Ensure helper validates integration existence,
facebookPageId, and pageAccessToken and throws descriptive Errors when missing.

Comment on lines +65 to +72
export const KnowledgeBaseParentCategory = {
...KnowledgeBaseCategory,

async childrens(category: ICategoryDocument, _args, { models }: IContext) {
return models.Category.find({
parentCategoryId: category._id,
}).sort({ title: 1 });
},
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Search for childrens/children usage in knowledgebase module
rg -n "childrens|children" --type ts backend/plugins/frontline_api/src/modules/knowledgebase/ | head -50

Repository: erxes/erxes

Length of output: 648


🏁 Script executed:

#!/bin/bash
# Find GraphQL schema/typedefs files in knowledgebase module
fd -e ts -e graphql -e gql backend/plugins/frontline_api/src/modules/knowledgebase/ | grep -E "(schema|typeDef|gql)" | head -20

Repository: erxes/erxes

Length of output: 584


🏁 Script executed:

#!/bin/bash
# Get a broader view of the knowledgebase module structure
find backend/plugins/frontline_api/src/modules/knowledgebase -type f -name "*.ts" -o -name "*.graphql" | head -30

Repository: erxes/erxes

Length of output: 1664


🏁 Script executed:

#!/bin/bash
# View the GraphQL schema around line 97
sed -n '90,105p' backend/plugins/frontline_api/src/modules/knowledgebase/graphql/schemas/knowledgeBaseTypeDefs.ts

Repository: erxes/erxes

Length of output: 418


🏁 Script executed:

#!/bin/bash
# Search for any client-side or other references to the childrens field
rg "childrens" --type ts --type tsx -B2 -A2 backend/

Repository: erxes/erxes

Length of output: 82


🏁 Script executed:

#!/bin/bash
# Search for all childrens references across the codebase
rg "childrens" --type ts -B1 -A1

Repository: erxes/erxes

Length of output: 817


🏁 Script executed:

#!/bin/bash
# Check for GraphQL queries that might use the childrens field
rg "childrens" --type-add 'gql:*.graphql' -t gql

Repository: erxes/erxes

Length of output: 37


Fix grammatical error: childrens should be children in both schema and resolver.

"Children" is already plural; "childrens" is not valid English. This naming error exists in two places and must be fixed together:

  1. GraphQL schema field (knowledgeBaseTypeDefs.ts line 97)
  2. Resolver implementation (category.ts line 68)
Changes required

In backend/plugins/frontline_api/src/modules/knowledgebase/graphql/schemas/knowledgeBaseTypeDefs.ts:

-      childrens: [KnowledgeBaseCategory]
+      children: [KnowledgeBaseCategory]

In backend/plugins/frontline_api/src/modules/knowledgebase/graphql/resolvers/customResolvers/category.ts:

-  async childrens(category: ICategoryDocument, _args, { models }: IContext) {
+  async children(category: ICategoryDocument, _args, { models }: IContext) {

Note: This is a breaking change for any API consumers using the childrens field. Ensure coordinated updates across dependent services.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export const KnowledgeBaseParentCategory = {
...KnowledgeBaseCategory,
async childrens(category: ICategoryDocument, _args, { models }: IContext) {
return models.Category.find({
parentCategoryId: category._id,
}).sort({ title: 1 });
},
export const KnowledgeBaseParentCategory = {
...KnowledgeBaseCategory,
async children(category: ICategoryDocument, _args, { models }: IContext) {
return models.Category.find({
parentCategoryId: category._id,
}).sort({ title: 1 });
},
🤖 Prompt for AI Agents
In
@backend/plugins/frontline_api/src/modules/knowledgebase/graphql/resolvers/customResolvers/category.ts
around lines 65 - 72, Rename the invalid plural field `childrens` to `children`
in both the GraphQL schema definition (change the field name in the type defs)
and the resolver object property (update KnowledgeBaseParentCategory's async
childrens(...) to async children(...)), update any internal
references/imports/usages to the new `children` name (including tests and other
resolvers), and run schema validation/GraphQL build to ensure no remaining
references to `childrens` remain; treat this as a breaking change for API
consumers and bump/change docs accordingly.

@sonarqubecloud
Copy link

Copy link
Contributor

@ellipsis-dev ellipsis-dev bot left a comment

Choose a reason for hiding this comment

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

Important

Looks good to me! 👍

Reviewed dab440f in 1 minute and 39 seconds. Click for details.
  • Reviewed 317 lines of code in 13 files
  • Skipped 0 files when reviewing.
  • Skipped posting 15 draft comments. View those below.
  • Modify your settings and rules to customize what types of comments Ellipsis leaves. And don't forget to react with 👍 or 👎 to teach Ellipsis.
1. backend/plugins/frontline_api/src/apollo/resolvers/mutations.ts:11
  • Draft comment:
    Minor formatting fix: added the missing semicolon in the knowledgeBaseMutations import.
  • Reason this comment was not posted:
    Confidence changes required: 33% <= threshold 50% None
2. backend/plugins/frontline_api/src/modules/integrations/instagram/@types/bots.ts:1
  • Draft comment:
    Removed Instagram bots type definitions (IBot, IBotDocument). Ensure that no parts of the code still rely on these types.
  • Reason this comment was not posted:
    Confidence changes required: 33% <= threshold 50% None
3. backend/plugins/frontline_api/src/modules/integrations/instagram/@types/comment_conversations.ts:1
  • Draft comment:
    Removed Instagram comment conversations type definitions. Confirm that conversation handling isn’t affected by this deletion.
  • Reason this comment was not posted:
    Confidence changes required: 33% <= threshold 50% None
4. backend/plugins/frontline_api/src/modules/integrations/instagram/@types/comment_conversations_reply.ts:1
  • Draft comment:
    Removed Instagram comment conversation reply types. Make sure that any functionality depending on these definitions is updated.
  • Reason this comment was not posted:
    Confidence changes required: 33% <= threshold 50% None
5. backend/plugins/frontline_api/src/modules/integrations/instagram/@types/conversationMessages.ts:1
  • Draft comment:
    Removed Instagram conversation message types. Verify that these types aren’t required by any message-handling modules.
  • Reason this comment was not posted:
    Confidence changes required: 33% <= threshold 50% None
6. backend/plugins/frontline_api/src/modules/integrations/instagram/@types/conversations.ts:1
  • Draft comment:
    Removed Instagram conversations type definitions. Ensure that conversation-related operations are not impacted.
  • Reason this comment was not posted:
    Confidence changes required: 33% <= threshold 50% None
7. backend/plugins/frontline_api/src/modules/integrations/instagram/@types/customers.ts:1
  • Draft comment:
    Removed Instagram customer type definitions. Verify that integrations now use updated customer structures if needed.
  • Reason this comment was not posted:
    Confidence changes required: 33% <= threshold 50% None
8. backend/plugins/frontline_api/src/modules/integrations/instagram/@types/logs.ts:1
  • Draft comment:
    Removed Instagram logs type definitions. Confirm that logging functionality is properly handled in the updated integration.
  • Reason this comment was not posted:
    Confidence changes required: 33% <= threshold 50% None
9. backend/plugins/frontline_api/src/modules/integrations/instagram/@types/postConversations.ts:1
  • Draft comment:
    Removed Instagram post conversation types. Ensure that any endpoints or logic using these types are updated accordingly.
  • Reason this comment was not posted:
    Confidence changes required: 33% <= threshold 50% None
10. backend/plugins/frontline_api/src/modules/integrations/instagram/@types/utils.ts:1
  • Draft comment:
    Removed Instagram utility functions for schema option wrapping. Confirm that schema creation elsewhere isn’t adversely affected.
  • Reason this comment was not posted:
    Confidence changes required: 33% <= threshold 50% None
11. backend/plugins/frontline_api/src/modules/knowledgebase/graphql/resolvers/customResolvers/category.ts:18
  • Draft comment:
    Updated the articles resolver to use models.Article.find(query) for fetching articles instead of models.Category.find. This aligns with the proper data model for articles.
  • Reason this comment was not posted:
    Comment did not seem useful. Confidence is useful = 0% <= threshold 50% This comment is purely informative, explaining a change that was made without asking for any specific action or providing a suggestion. It doesn't align with the rules for useful comments.
12. backend/plugins/frontline_api/src/modules/knowledgebase/graphql/resolvers/customResolvers/category.ts:40
  • Draft comment:
    Changed the firstTopic resolver to use models.Topic.findOne instead of models.Category.findOne, ensuring the correct topic is retrieved.
  • Reason this comment was not posted:
    Comment did not seem useful. Confidence is useful = 0% <= threshold 50% This comment is purely informative, explaining what change was made without providing any actionable feedback or suggestions. It does not ask for confirmation or suggest improvements.
13. backend/plugins/frontline_api/src/modules/knowledgebase/graphql/resolvers/customResolvers/category.ts:58
  • Draft comment:
    Refactored the numOfArticles resolver to use models.Article.countDocuments(query) for an accurate article count from the correct collection.
  • Reason this comment was not posted:
    Comment did not seem useful. Confidence is useful = 0% <= threshold 50% This comment is purely informative, as it simply acknowledges a good refactoring without providing any actionable feedback or suggestions. It does not align with the rules for useful comments.
14. backend/plugins/frontline_api/src/modules/knowledgebase/graphql/resolvers/customResolvers/topic.ts:20
  • Draft comment:
    Updated the categories (and parentCategories) resolvers to use models.Category.find instead of models.Topic.find, which correctly reflects the schema structure.
  • Reason this comment was not posted:
    Comment did not seem useful. Confidence is useful = 0% <= threshold 50% This comment is purely informative, explaining a change that was made. It does not provide a suggestion, ask for confirmation, or point out a potential issue. According to the rules, purely informative comments should be removed.
15. backend/plugins/frontline_api/src/modules/knowledgebase/graphql/resolvers/queries/knowledgeBaseQueries.ts:78
  • Draft comment:
    Adjusted the deletion of the query field from 'selector.topicIds' to 'delete selector.topicId' to match the buildQuery transformation. This prevents unintended filtering.
  • Reason this comment was not posted:
    Comment did not seem useful. Confidence is useful = 0% <= threshold 50% This comment is purely informative, explaining a change that was made. It does not ask for confirmation, suggest improvements, or identify potential issues.

Workflow ID: wflow_58ivQC3LE6JfviKQ

You can customize Ellipsis by changing your verbosity settings, reacting with 👍 or 👎, replying to comments, or adding code review rules.

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

🤖 Fix all issues with AI agents
In
@backend/plugins/frontline_api/src/modules/knowledgebase/graphql/resolvers/customResolvers/category.ts:
- Around line 68-72: Rename the incorrect plural field `childrens` to `children`
in both the GraphQL type defs and resolver: change the field name `childrens` in
the knowledgeBase type definition to `children` and rename the resolver method
`childrens` to `children` inside the Category resolver so the schema and
resolver names match; update any resolver export/mapping that references
`childrens` to `children` and adjust any other code/tests that query the old
`childrens` field to use `children`.

In
@backend/plugins/frontline_api/src/modules/knowledgebase/graphql/resolvers/queries/knowledgeBaseQueries.ts:
- Around line 197-203: The resolver knowledgeBaseTopicsTotalCount currently
calls models.Topic.countDocuments({}) and ignores any filter args; change it to
accept and forward the incoming filter (e.g., _args or _args.filters) the same
way knowledgeBaseArticlesTotalCount and knowledgeBaseCategoriesTotalCount do so
that models.Topic.countDocuments receives the constructed filter object instead
of an empty literal, ensuring filtered counts are correct.
- Around line 21-27: The query builds regexes from unescaped user input
(args.searchValue) into qry.$or, which risks ReDoS and wrong matches; escape
regex metacharacters from args.searchValue before creating the RegExp and remove
the unnecessary leading/trailing ".*" wrappers (use a case-insensitive RegExp
that matches the escaped substring). Update the code paths that set qry.$or to
use the escaped value (replace direct interpolation of args.searchValue) so each
RegExp is constructed from the escaped string with the 'i' flag and handles
empty/whitespace-only inputs as before.
- Around line 14-18: The plural-to-field mapping in the keys.forEach loop is
incorrect because key.replace('s', '') removes the first 's' anywhere in the
string; update the logic that derives field from key (used when setting
qry[field] = { $in: args[key] }) to only strip a trailing 's' — e.g., check
key.endsWith('s') and use key.slice(0, -1) or use key.replace(/s$/, '') — and
keep key unchanged if it does not end with 's', ensuring fields like "status"
are not mangled.
🧹 Nitpick comments (2)
backend/plugins/frontline_api/src/modules/knowledgebase/graphql/resolvers/queries/knowledgeBaseQueries.ts (1)

5-7: Add type annotations to findDetail helper.

The function lacks TypeScript types for its parameters. Consider adding proper typing for better maintainability and type safety.

Suggested improvement
-const findDetail = async (model, _id) => {
-  return await model.findOne({ $or: [{ _id }, { code: _id }] });
+const findDetail = async (model: { findOne: (query: object) => Promise<unknown> }, _id: string) => {
+  return model.findOne({ $or: [{ _id }, { code: _id }] });
};
backend/plugins/frontline_api/src/modules/knowledgebase/graphql/resolvers/customResolvers/category.ts (1)

23-38: Duplicate author IDs are returned without deduplication.

If multiple articles in a category share the same createdBy, the resolver returns duplicate User references. Consider deduplicating the author IDs.

Proposed fix
  async authors(category: ICategoryDocument, _args, { models }: IContext) {
    const articles = await models.Article.find(
      {
        categoryId: category._id,
        status: { $in: [PUBLISH_STATUSES.PUBLISH, PUBLISH_STATUSES.DRAFT] },
      },
      { createdBy: 1 }
    );

-   const authorIds = articles.map((article) => article.createdBy);
+   const authorIds = [...new Set(articles.map((article) => article.createdBy))];

    return (authorIds || []).map((_id) => ({
      __typename: 'User',
      _id,
    }));
  },
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between efe8ef3 and dab440f.

📒 Files selected for processing (4)
  • backend/plugins/frontline_api/src/apollo/resolvers/mutations.ts
  • backend/plugins/frontline_api/src/modules/knowledgebase/graphql/resolvers/customResolvers/category.ts
  • backend/plugins/frontline_api/src/modules/knowledgebase/graphql/resolvers/customResolvers/topic.ts
  • backend/plugins/frontline_api/src/modules/knowledgebase/graphql/resolvers/queries/knowledgeBaseQueries.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • backend/plugins/frontline_api/src/apollo/resolvers/mutations.ts
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursorrules)

**/*.{ts,tsx}: Write concise, technical TypeScript code with accurate examples
Use functional and declarative programming patterns; avoid classes
Prefer iteration and modularization over code duplication
Use descriptive variable names with auxiliary verbs (e.g., isLoading, hasError)
Structure files: exported component, utils, contexts, hooks, types
Avoid console logs
Always use absolute paths when importing
Favor named exports for components
Use TypeScript for all code; prefer interfaces over types
Avoid enums; use maps instead
Use functional components with TypeScript interfaces
Use the 'function' keyword for pure functions
Avoid unnecessary curly braces in conditionals; use concise syntax for simple statements

Files:

  • backend/plugins/frontline_api/src/modules/knowledgebase/graphql/resolvers/customResolvers/topic.ts
  • backend/plugins/frontline_api/src/modules/knowledgebase/graphql/resolvers/customResolvers/category.ts
  • backend/plugins/frontline_api/src/modules/knowledgebase/graphql/resolvers/queries/knowledgeBaseQueries.ts
🧬 Code graph analysis (3)
backend/plugins/frontline_api/src/modules/knowledgebase/graphql/resolvers/customResolvers/topic.ts (2)
backend/plugins/frontline_api/src/connectionResolvers.ts (1)
  • IContext (237-241)
backend/plugins/frontline_api/src/modules/knowledgebase/@types/topic.ts (1)
  • ITopicDocument (16-18)
backend/plugins/frontline_api/src/modules/knowledgebase/graphql/resolvers/customResolvers/category.ts (3)
backend/plugins/frontline_api/src/modules/knowledgebase/@types/category.ts (1)
  • ICategoryDocument (14-16)
backend/plugins/frontline_api/src/connectionResolvers.ts (1)
  • IContext (237-241)
backend/plugins/frontline_api/src/modules/knowledgebase/db/definitions/constant.ts (1)
  • PUBLISH_STATUSES (2-7)
backend/plugins/frontline_api/src/modules/knowledgebase/graphql/resolvers/queries/knowledgeBaseQueries.ts (4)
backend/plugins/frontline_api/src/connectionResolvers.ts (1)
  • IContext (237-241)
backend/plugins/frontline_api/src/modules/knowledgebase/graphql/resolvers/customResolvers/category.ts (1)
  • articles (6-21)
backend/erxes-api-shared/src/utils/mongo/mongoose-utils.ts (1)
  • defaultPaginate (73-92)
backend/plugins/frontline_api/src/modules/knowledgebase/graphql/resolvers/customResolvers/topic.ts (1)
  • categories (19-23)
⏰ 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). (2)
  • GitHub Check: frontline_api-ci
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (11)
backend/plugins/frontline_api/src/modules/knowledgebase/graphql/resolvers/queries/knowledgeBaseQueries.ts (3)

50-88: LGTM for knowledgeBaseArticles resolver logic.

The topic-to-category resolution, dynamic sorting, and pagination are correctly implemented. Good use of defaultPaginate consistent with codebase patterns.


90-96: LGTM!

knowledgeBaseArticleDetail correctly delegates to findDetail with fallback to code lookup.


98-108: Race condition on concurrent view count increments.

While MongoDB's $inc is atomic, high-traffic articles may experience write contention. For analytics-heavy use cases, consider eventual consistency patterns (e.g., batched updates or a separate analytics collection).

This is acceptable for now but worth noting for scale.

backend/plugins/frontline_api/src/modules/knowledgebase/graphql/resolvers/customResolvers/topic.ts (5)

4-7: LGTM!

The __resolveReference resolver correctly implements federation reference resolution by fetching the topic by _id.


9-16: LGTM!

The brand resolver correctly returns a federation reference object when brandId exists, using short-circuit evaluation.


19-23: LGTM!

The categories resolver correctly fetches related categories sorted by title, consistent with the pattern in knowledgeBaseQueries.ts.


25-36: LGTM!

Good handling of multiple falsy states for parentCategoryId (null, non-existent, empty string) to identify root-level categories.


38-40: LGTM!

Simple and correct fallback for color field.

backend/plugins/frontline_api/src/modules/knowledgebase/graphql/resolvers/customResolvers/category.ts (3)

6-21: LGTM!

The articles resolver correctly applies status filtering with sensible defaults (PUBLISH and DRAFT) and allows override via args.


40-42: LGTM!

Simple and correct topic resolution.


44-62: LGTM!

The numOfArticles resolver correctly counts articles with consistent status filtering logic.

Comment on lines +68 to +72
async childrens(category: ICategoryDocument, _args, { models }: IContext) {
return models.Category.find({
parentCategoryId: category._id,
}).sort({ title: 1 });
},
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# First, let's read the actual file to confirm the method name
cat -n backend/plugins/frontline_api/src/modules/knowledgebase/graphql/resolvers/customResolvers/category.ts | sed -n '65,75p'

Repository: erxes/erxes

Length of output: 376


🏁 Script executed:

#!/bin/bash
# Search for GraphQL type definitions related to Category
find backend/plugins/frontline_api -type f \( -name "*.ts" -o -name "*.graphql" \) | xargs grep -l "type Category" | head -20

Repository: erxes/erxes

Length of output: 37


🏁 Script executed:

#!/bin/bash
# Search for all usages of "childrens" in the codebase
rg -n "childrens" backend/plugins/frontline_api --type ts

Repository: erxes/erxes

Length of output: 378


🏁 Script executed:

#!/bin/bash
# Search for GraphQL schema/type definition files for category
rg -n "childrens|children" backend/plugins/frontline_api -g '*type*' -g '*schema*' -g '*typeDef*' --type ts

Repository: erxes/erxes

Length of output: 37


🏁 Script executed:

#!/bin/bash
# Check the GraphQL schema file to see the context around the childrens field
cat -n backend/plugins/frontline_api/src/modules/knowledgebase/graphql/schemas/knowledgeBaseTypeDefs.ts | sed -n '90,105p'

Repository: erxes/erxes

Length of output: 530


🏁 Script executed:

#!/bin/bash
# Search for any other references to childrens in the entire codebase (not just backend/plugins/frontline_api)
rg -n "childrens" --type ts

Repository: erxes/erxes

Length of output: 378


🏁 Script executed:

#!/bin/bash
# Check if there are any frontend/client code that queries this field
rg -n "childrens" --type ts --type tsx

Repository: erxes/erxes

Length of output: 82


🏁 Script executed:

#!/bin/bash
# Search for GraphQL queries or usages of the childrens field in client code
rg -n "childrens" --type-list

Repository: erxes/erxes

Length of output: 444


🏁 Script executed:

#!/bin/bash
# Search more broadly for childrens in all files
rg -n "childrens" --no-require-git

Repository: erxes/erxes

Length of output: 378


🏁 Script executed:

#!/bin/bash
# Check if there are test files that reference childrens
find . -type f \( -name "*.test.ts" -o -name "*.spec.ts" -o -name "*.test.js" -o -name "*.spec.js" \) | xargs rg -n "childrens" 2>/dev/null || echo "No test references found"

Repository: erxes/erxes

Length of output: 378


🏁 Script executed:

#!/bin/bash
# Let's verify this is indeed a typo and not an intentional naming choice
# by checking if there are any comments or documentation around it
cat -n backend/plugins/frontline_api/src/modules/knowledgebase/graphql/schemas/knowledgeBaseTypeDefs.ts | sed -n '80,110p'

Repository: erxes/erxes

Length of output: 977


🏁 Script executed:

#!/bin/bash
# Also check if there are any other child-related fields to understand the naming pattern
rg -n "child" backend/plugins/frontline_api/src/modules/knowledgebase/graphql/schemas/knowledgeBaseTypeDefs.ts -i

Repository: erxes/erxes

Length of output: 98


Rename childrens to children in both the GraphQL schema and resolver.

"Children" is already the plural form of "child"; "childrens" is grammatically incorrect. Update the field name in both locations:

  • backend/plugins/frontline_api/src/modules/knowledgebase/graphql/schemas/knowledgeBaseTypeDefs.ts (line 97)
  • backend/plugins/frontline_api/src/modules/knowledgebase/graphql/resolvers/customResolvers/category.ts (line 68)
Proposed fix

Schema:

-      childrens: [KnowledgeBaseCategory]
+      children: [KnowledgeBaseCategory]

Resolver:

-  async childrens(category: ICategoryDocument, _args, { models }: IContext) {
+  async children(category: ICategoryDocument, _args, { models }: IContext) {
     return models.Category.find({
       parentCategoryId: category._id,
     }).sort({ title: 1 });
   },
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
async childrens(category: ICategoryDocument, _args, { models }: IContext) {
return models.Category.find({
parentCategoryId: category._id,
}).sort({ title: 1 });
},
async children(category: ICategoryDocument, _args, { models }: IContext) {
return models.Category.find({
parentCategoryId: category._id,
}).sort({ title: 1 });
},
🤖 Prompt for AI Agents
In
@backend/plugins/frontline_api/src/modules/knowledgebase/graphql/resolvers/customResolvers/category.ts
around lines 68 - 72, Rename the incorrect plural field `childrens` to
`children` in both the GraphQL type defs and resolver: change the field name
`childrens` in the knowledgeBase type definition to `children` and rename the
resolver method `childrens` to `children` inside the Category resolver so the
schema and resolver names match; update any resolver export/mapping that
references `childrens` to `children` and adjust any other code/tests that query
the old `childrens` field to use `children`.

Comment on lines +14 to +18
keys.forEach((key) => {
if (args[key] && args[key].length > 0) {
const field = key.replace('s', '');
qry[field] = { $in: args[key] };
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Incorrect key-to-field mapping for pluralized keys.

The logic key.replace('s', '') is flawed—it replaces the first 's' in the string, not the trailing 's'. For example, 'status' would become 'tatus' instead of remaining unchanged, and 'codes' becomes 'code' (correct by accident), but 'categoryIds' becomes 'categoryId' only because the first 's' is the trailing one in this case.

Consider using key.replace(/s$/, '') or key.slice(0, -1) to remove only the trailing character.

Proposed fix
  keys.forEach((key) => {
    if (args[key] && args[key].length > 0) {
-      const field = key.replace('s', '');
+      const field = key.slice(0, -1);
      qry[field] = { $in: args[key] };
    }
  });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
keys.forEach((key) => {
if (args[key] && args[key].length > 0) {
const field = key.replace('s', '');
qry[field] = { $in: args[key] };
}
keys.forEach((key) => {
if (args[key] && args[key].length > 0) {
const field = key.slice(0, -1);
qry[field] = { $in: args[key] };
}
🤖 Prompt for AI Agents
In
@backend/plugins/frontline_api/src/modules/knowledgebase/graphql/resolvers/queries/knowledgeBaseQueries.ts
around lines 14 - 18, The plural-to-field mapping in the keys.forEach loop is
incorrect because key.replace('s', '') removes the first 's' anywhere in the
string; update the logic that derives field from key (used when setting
qry[field] = { $in: args[key] }) to only strip a trailing 's' — e.g., check
key.endsWith('s') and use key.slice(0, -1) or use key.replace(/s$/, '') — and
keep key unchanged if it does not end with 's', ensuring fields like "status"
are not mangled.

Comment on lines +21 to +27
if (args.searchValue && args.searchValue.trim()) {
qry.$or = [
{ title: { $regex: `.*${args.searchValue.trim()}.*`, $options: 'i' } },
{ content: { $regex: `.*${args.searchValue.trim()}.*`, $options: 'i' } },
{ summary: { $regex: `.*${args.searchValue.trim()}.*`, $options: 'i' } },
];
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Potential ReDoS vulnerability with unescaped regex input.

User-provided searchValue is directly interpolated into a regex pattern without escaping special characters. This can lead to regex denial-of-service (ReDoS) attacks or unexpected query behavior if the input contains regex metacharacters like ., *, +, (, etc.

Proposed fix — escape regex special characters
+const escapeRegex = (str: string) => str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
+
 const buildQuery = (args: any) => {
   const qry: any = {};
   // ...
   if (args.searchValue && args.searchValue.trim()) {
+    const escaped = escapeRegex(args.searchValue.trim());
     qry.$or = [
-      { title: { $regex: `.*${args.searchValue.trim()}.*`, $options: 'i' } },
-      { content: { $regex: `.*${args.searchValue.trim()}.*`, $options: 'i' } },
-      { summary: { $regex: `.*${args.searchValue.trim()}.*`, $options: 'i' } },
+      { title: { $regex: escaped, $options: 'i' } },
+      { content: { $regex: escaped, $options: 'i' } },
+      { summary: { $regex: escaped, $options: 'i' } },
     ];
   }

Note: The .* wrapper is also redundant since regex matching is substring-based by default.

🤖 Prompt for AI Agents
In
@backend/plugins/frontline_api/src/modules/knowledgebase/graphql/resolvers/queries/knowledgeBaseQueries.ts
around lines 21 - 27, The query builds regexes from unescaped user input
(args.searchValue) into qry.$or, which risks ReDoS and wrong matches; escape
regex metacharacters from args.searchValue before creating the RegExp and remove
the unnecessary leading/trailing ".*" wrappers (use a case-insensitive RegExp
that matches the escaped substring). Update the code paths that set qry.$or to
use the escaped value (replace direct interpolation of args.searchValue) so each
RegExp is constructed from the escaped string with the 'i' flag and handles
empty/whitespace-only inputs as before.

Comment on lines +197 to +203
async knowledgeBaseTopicsTotalCount(
_root,
_args,
{ models }: IContext
) {
return models.Topic.countDocuments({});
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

knowledgeBaseTopicsTotalCount ignores filter arguments.

Unlike knowledgeBaseArticlesTotalCount and knowledgeBaseCategoriesTotalCount, this resolver passes an empty object {} to countDocuments, ignoring any filters that might be passed in _args. This inconsistency could cause incorrect counts when filters are applied.

Proposed fix for consistency
  async knowledgeBaseTopicsTotalCount(
    _root,
-   _args,
+   args,
    { models }: IContext
  ) {
-   return models.Topic.countDocuments({});
+   const qry = buildQuery(args);
+   return models.Topic.countDocuments(qry);
  }
🤖 Prompt for AI Agents
In
@backend/plugins/frontline_api/src/modules/knowledgebase/graphql/resolvers/queries/knowledgeBaseQueries.ts
around lines 197 - 203, The resolver knowledgeBaseTopicsTotalCount currently
calls models.Topic.countDocuments({}) and ignores any filter args; change it to
accept and forward the incoming filter (e.g., _args or _args.filters) the same
way knowledgeBaseArticlesTotalCount and knowledgeBaseCategoriesTotalCount do so
that models.Topic.countDocuments receives the constructed filter object instead
of an empty literal, ensuring filtered counts are correct.

@uuganaa1007 uuganaa1007 merged commit 0ce2ae7 into main Jan 13, 2026
9 of 10 checks passed
@uuganaa1007 uuganaa1007 deleted the knowledgebase branch January 13, 2026 11:33
@coderabbitai coderabbitai bot mentioned this pull request Jan 14, 2026
@coderabbitai coderabbitai bot mentioned this pull request Feb 3, 2026
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.

2 participants