Conversation
There was a problem hiding this comment.
Sorry @Batuktech, you have reached your weekly rate limit of 500000 diff characters.
Please try again later or upgrade to continue using Sourcery
There was a problem hiding this comment.
Your free trial has ended. If you'd like to continue receiving code reviews, you can add a payment method here.
📝 WalkthroughWalkthroughThis 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
Sequence DiagramsequenceDiagram
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
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
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. Comment |
There was a problem hiding this comment.
Caution
Changes requested ❌
Reviewed everything up to 17670ab in 2 minutes and 59 seconds. Click for details.
- Reviewed
1557lines of code in25files - Skipped
0files when reviewing. - Skipped posting
10draft 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 afieldfunction? 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/modules/knowledgebase/db/utils' actually exists or exports afieldfunction. The comment makes an assumption that may not be correct. I cannot verify from the diff alone whether 'fieldfunction. The comment assumes this path exists and is the correct one to use, but this might not be true. Thefieldutility 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 samefieldfunction. 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/utilsactually 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/utilsfile 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/utilsexists 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 thecategoriesandparentCategoriesresolvers usemodels.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 usestopicId: topic._idwhich 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 ofmodels.Topic.findin 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 ofmodels.Topic.findin 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 forknowledgeBaseQueries. - 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 theno-extra-semirule 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 by changing your verbosity settings, reacting with 👍 or 👎, replying to comments, or adding code review rules.
|
|
||
| return await models.Article.findOneAndUpdate( | ||
| { _id }, | ||
| {$set: doc} |
There was a problem hiding this comment.
Consider adding the { new: true } option to findOneAndUpdate to return the updated document.
| {$set: doc} | |
| {$set: doc}, { new: true } |
| } | ||
|
|
||
| await models.Category.deleteMany({ | ||
| categoryId: _id |
There was a problem hiding this comment.
Use parentCategoryId (not categoryId) in the deleteMany filter when removing child categories.
| categoryId: _id | |
| parentCategoryId: _id |
| query.status = status; | ||
| } | ||
|
|
||
| return models.Category.find(query).sort({ |
There was a problem hiding this comment.
The articles resolver is querying models.Category instead of models.Article. It should fetch articles for the category.
| 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 }); |
There was a problem hiding this comment.
The firstTopic resolver queries models.Category; it should query models.Topic to retrieve the related topic.
| return models.Category.findOne({ _id: category.topicId }); | |
| return models.Topic.findOne({ _id: category.topicId }); |
| user._id | ||
| ); | ||
|
|
||
| ; |
There was a problem hiding this comment.
Remove the stray semicolon in the knowledgeBaseTopicsEdit mutation.
| ; |
| throw new Error('Topic not found'); | ||
| } | ||
|
|
||
| const categories = await models.Topic.find({ |
There was a problem hiding this comment.
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' |
There was a problem hiding this comment.
The import statement is missing a semicolon at the end. Add a semicolon for consistency with the other import statements.
| import { knowledgeBaseMutations } from '@/knowledgebase/graphql/resolvers/mutations/knowledgeBaseMutations' | |
| import { knowledgeBaseMutations } from '@/knowledgebase/graphql/resolvers/mutations/knowledgeBaseMutations'; |
| authors: [User] | ||
| numOfArticles(status: String): Float | ||
|
|
||
| childrens: [KnowledgeBaseCategory] |
There was a problem hiding this comment.
Typo: Consider renaming 'childrens' to 'children' for proper pluralization.
There was a problem hiding this comment.
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 addingas constfor stricter type safety.Adding
as constpreserves literal types instead of widening tostring, 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 makingtitlerequired.All fields in
ICategoryare optional, which may allow creating categories without essential data. Typically,titlewould 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: Duplicatecodefield and consider makingtitlerequired.
- The
codefield is already defined inICommonFields(whichITopicDocumentextends), creating redundancy.- Similar to
ICategory, consider whethertitleshould 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
AddandEditmutations.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 dedicatedexistscheck.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 makingcreatedByandmodifiedByoptional to prevent validation errors.The
fieldutility applies/\S+/validation to non-optional String fields. While current code enforcesuserIdthroughcreateDoc/updateDocmethods, 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 exportingIFormCodesinterface.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_idfield.The
_idfield 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:createDocsignature allows optionaluserIdbut throws if not provided.The method signature declares
userIdas optional (userId?: string), but the implementation immediately throws if it's not supplied. Consider makinguserIdrequired 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:updateDocallows optionaluserIdbut throws if not provided.Apply the same fix as
createDoc- makeuserIdrequired 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 —getArticlealready throws if not found.The
getArticlemethod throws an error when the article is not found, making the subsequentif(!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
searchValueis 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
📒 Files selected for processing (25)
backend/plugins/frontline_api/src/apollo/resolvers/mutations.tsbackend/plugins/frontline_api/src/apollo/resolvers/queries.tsbackend/plugins/frontline_api/src/apollo/resolvers/resolvers.tsbackend/plugins/frontline_api/src/apollo/schema/schema.tsbackend/plugins/frontline_api/src/apollo/typeDefs.tsbackend/plugins/frontline_api/src/connectionResolvers.tsbackend/plugins/frontline_api/src/modules/knowledgebase/@types/article.tsbackend/plugins/frontline_api/src/modules/knowledgebase/@types/category.tsbackend/plugins/frontline_api/src/modules/knowledgebase/@types/common.tsbackend/plugins/frontline_api/src/modules/knowledgebase/@types/topic.tsbackend/plugins/frontline_api/src/modules/knowledgebase/db/definitions/article.tsbackend/plugins/frontline_api/src/modules/knowledgebase/db/definitions/category.tsbackend/plugins/frontline_api/src/modules/knowledgebase/db/definitions/constant.tsbackend/plugins/frontline_api/src/modules/knowledgebase/db/definitions/topic.tsbackend/plugins/frontline_api/src/modules/knowledgebase/db/models/Article.tsbackend/plugins/frontline_api/src/modules/knowledgebase/db/models/Category.tsbackend/plugins/frontline_api/src/modules/knowledgebase/db/models/Topic.tsbackend/plugins/frontline_api/src/modules/knowledgebase/db/utils.tsbackend/plugins/frontline_api/src/modules/knowledgebase/graphql/resolvers/customResolvers/article.tsbackend/plugins/frontline_api/src/modules/knowledgebase/graphql/resolvers/customResolvers/category.tsbackend/plugins/frontline_api/src/modules/knowledgebase/graphql/resolvers/customResolvers/topic.tsbackend/plugins/frontline_api/src/modules/knowledgebase/graphql/resolvers/mutations/knowledgeBaseMutations.tsbackend/plugins/frontline_api/src/modules/knowledgebase/graphql/resolvers/queries/knowledgeBaseQueries.tsbackend/plugins/frontline_api/src/modules/knowledgebase/graphql/schemas/knowledgeBaseTypeDefs.tsbackend/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.tsbackend/plugins/frontline_api/src/modules/knowledgebase/db/definitions/category.tsbackend/plugins/frontline_api/src/apollo/typeDefs.tsbackend/plugins/frontline_api/src/modules/knowledgebase/db/definitions/topic.tsbackend/plugins/frontline_api/src/modules/knowledgebase/db/definitions/article.tsbackend/plugins/frontline_api/src/modules/knowledgebase/@types/common.tsbackend/plugins/frontline_api/src/apollo/resolvers/mutations.tsbackend/plugins/frontline_api/src/modules/knowledgebase/graphql/resolvers/customResolvers/topic.tsbackend/plugins/frontline_api/src/modules/knowledgebase/@types/category.tsbackend/plugins/frontline_api/src/apollo/resolvers/queries.tsbackend/plugins/frontline_api/src/modules/knowledgebase/graphql/resolvers/customResolvers/category.tsbackend/plugins/frontline_api/src/modules/knowledgebase/graphql/schemas/knowledgeBaseTypeDefs.tsbackend/plugins/frontline_api/src/modules/knowledgebase/@types/article.tsbackend/plugins/frontline_api/src/modules/knowledgebase/db/utils.tsbackend/plugins/frontline_api/src/modules/knowledgebase/db/models/Article.tsbackend/plugins/frontline_api/src/modules/knowledgebase/@types/topic.tsbackend/plugins/frontline_api/src/apollo/resolvers/resolvers.tsbackend/plugins/frontline_api/src/modules/knowledgebase/graphql/resolvers/mutations/knowledgeBaseMutations.tsbackend/plugins/frontline_api/src/modules/knowledgebase/db/models/Category.tsbackend/plugins/frontline_api/src/apollo/schema/schema.tsbackend/plugins/frontline_api/src/modules/knowledgebase/graphql/resolvers/customResolvers/article.tsbackend/plugins/frontline_api/src/modules/knowledgebase/db/models/Topic.tsbackend/plugins/frontline_api/src/modules/knowledgebase/db/definitions/constant.tsbackend/plugins/frontline_api/src/connectionResolvers.tsbackend/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:codefield is properly included incommonFields.The index on
codeis valid. The field is defined inconstant.tsas part ofcommonFieldswithsparse: trueandunique: truealready 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
commonFieldsfor 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__resolveReferenceimplementation.Correctly fetches the article document by
_idfor 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
parentCategoryIdon child categories when a parent is removed, preventing orphaned references.
165-169: ReconsiderskipPermission: truefor knowledge base mutations — these are administrative operations.While
skipPermission: trueis 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 onPUBLISH_STATUSESdefinition.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
__resolveReferenceimplementation correctly fetches a topic by_idfor 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
IModelsinterface 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
findDetailhelper correctly supports lookup by both_idandcodefields using$or.
| @@ -0,0 +1,19 @@ | |||
| import { Schema } from 'mongoose'; | |||
| import { field } from '~/modules/integrations/call/db/utils'; | |||
There was a problem hiding this comment.
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.
| 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'; | |||
There was a problem hiding this comment.
🛠️ 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"
fiRepository: 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.
| ): Promise<IArticleDocument>; | ||
| removeDoc(_id: string): void; |
There was a problem hiding this comment.
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.
| ): 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).
| return await models.Article.findOneAndUpdate( | ||
| { _id }, | ||
| {$set: doc} | ||
| ); |
There was a problem hiding this comment.
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.
| if (childrenCounts > 0) { | ||
| throw new Error('Cannot change category. this is parent tag'); | ||
| } |
There was a problem hiding this comment.
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.
| 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.
...lugins/frontline_api/src/modules/knowledgebase/graphql/resolvers/customResolvers/category.ts
Show resolved
Hide resolved
...d/plugins/frontline_api/src/modules/knowledgebase/graphql/resolvers/customResolvers/topic.ts
Show resolved
Hide resolved
...d/plugins/frontline_api/src/modules/knowledgebase/graphql/resolvers/customResolvers/topic.ts
Show resolved
Hide resolved
...ns/frontline_api/src/modules/knowledgebase/graphql/resolvers/queries/knowledgeBaseQueries.ts
Show resolved
Hide resolved
| authors: [User] | ||
| numOfArticles(status: String): Float | ||
|
|
||
| childrens: [KnowledgeBaseCategory] |
There was a problem hiding this comment.
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.
| 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.
There was a problem hiding this comment.
Caution
Changes requested ❌
Reviewed 5b2d99a in 3 minutes and 0 seconds. Click for details.
- Reviewed
517lines of code in14files - Skipped
0files when reviewing. - Skipped posting
12draft 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_idfields are in completely different contexts:IPersistentMenus._idappears to be an identifier for menu items (possibly just an index or menu item ID), whileIBotDocument._idis the MongoDB document ID (from theDocumentinterface). 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 usednumberinstead ofstringfor 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_idfields serve completely different purposes in different contexts.IPersistentMenusis not a MongoDB document - it's just a plain interface for menu items, so usingnumberas 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_idfields 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? AddingRecord<string, any>doesn't actually improve type safety much sinceanystill 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 implicitany- 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 usesany. 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 stillany. Perhaps this is a reasonable suggestion for consistency with TypeScript best practices. While making types explicit can be good practice, the suggested typeRecord<string, any>provides minimal actual type safety improvement over implicitany. 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 implicitanyto explicitRecord<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%<= threshold50%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 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; |
There was a problem hiding this comment.
Use lowercase string instead of String for parentId to adhere to TypeScript best practices.
| parentId: String; | |
| parentId: string; |
| content: string; | ||
| integrationId: string; | ||
| customerId?: string; | ||
| permalink_url: String; |
There was a problem hiding this comment.
Use lowercase string instead of String for permalink_url for consistency.
| permalink_url: String; | |
| permalink_url: string; |
There was a problem hiding this comment.
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 replacinganywith more specific types.Using
anyforattachmentsandbotDatareduces type safety. Consider defining proper interfaces or at least usingunknownor a more specific type likeRecord<string, unknown>to maintain type checking.♻️ Suggested improvement
- attachments?: any; + attachments?: IAttachment[];- botData?: any; + botData?: Record<string, unknown>;You may want to define an
IAttachmentinterface 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 unusedSchemaimport.
Schemais 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 replacinganywith more specific types orunknown.Using
anyforvalueandspecialValuebypasses TypeScript's type checking. If the structure of these fields is truly unknown at compile time, preferunknownto 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 usingSchema.Types.Mixedor a Map schema forreactionCounts.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 usingattachmentSchemaforpdfAttachmentfor consistency.The
pdfAttachmentfield uses{ type: Object }which bypasses schema validation. SinceattachmentSchemais already imported and used forimageandattachments, 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 replacinganywith a more specific type.Using
anybypasses type safety. If the attachment structure is known, define an interface. If it's truly dynamic, considerunknownorRecord<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
schemaparameter 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:isResolvedshould be typed asboolean.The field name clearly indicates a boolean state (resolved vs unresolved). Using
anyloses 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: Unusedsubdomainparameter and fetch-only variables.
subdomainis destructured but unused inknowledgeBaseTopicsAddandknowledgeBaseTopicsRemove. Thetopicvariable 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: UnusedsubdomainandkbCategoryvariables in category mutations.Same pattern as Topic mutations:
subdomainis destructured but unused, andkbCategoryon 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$inoperator with single value.Using
$inwith 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
AddandEditmutations. Extract to a helper function to follow DRY principle. Also, there's inconsistent formatting (if(vsif ().♻️ 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: Unusedsubdomainand fetch-only variables in article mutations.Consistent with other mutations,
subdomainis unused in Add/Edit/Remove. ThekbArticlevariable 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
📒 Files selected for processing (16)
backend/plugins/frontline_api/src/modules/integrations/instagram/@types/bots.tsbackend/plugins/frontline_api/src/modules/integrations/instagram/@types/comment_conversations.tsbackend/plugins/frontline_api/src/modules/integrations/instagram/@types/comment_conversations_reply.tsbackend/plugins/frontline_api/src/modules/integrations/instagram/@types/conversationMessages.tsbackend/plugins/frontline_api/src/modules/integrations/instagram/@types/conversations.tsbackend/plugins/frontline_api/src/modules/integrations/instagram/@types/customers.tsbackend/plugins/frontline_api/src/modules/integrations/instagram/@types/logs.tsbackend/plugins/frontline_api/src/modules/integrations/instagram/@types/postConversations.tsbackend/plugins/frontline_api/src/modules/integrations/instagram/@types/utils.tsbackend/plugins/frontline_api/src/modules/integrations/instagram/routes.tsbackend/plugins/frontline_api/src/modules/integrations/instagram/utils.tsbackend/plugins/frontline_api/src/modules/knowledgebase/db/definitions/article.tsbackend/plugins/frontline_api/src/modules/knowledgebase/db/definitions/category.tsbackend/plugins/frontline_api/src/modules/knowledgebase/db/definitions/constant.tsbackend/plugins/frontline_api/src/modules/knowledgebase/db/definitions/topic.tsbackend/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.tsbackend/plugins/frontline_api/src/modules/integrations/instagram/@types/postConversations.tsbackend/plugins/frontline_api/src/modules/integrations/instagram/@types/comment_conversations_reply.tsbackend/plugins/frontline_api/src/modules/knowledgebase/db/definitions/topic.tsbackend/plugins/frontline_api/src/modules/integrations/instagram/@types/customers.tsbackend/plugins/frontline_api/src/modules/integrations/instagram/@types/conversations.tsbackend/plugins/frontline_api/src/modules/integrations/instagram/@types/bots.tsbackend/plugins/frontline_api/src/modules/knowledgebase/graphql/resolvers/mutations/knowledgeBaseMutations.tsbackend/plugins/frontline_api/src/modules/knowledgebase/db/definitions/article.tsbackend/plugins/frontline_api/src/modules/integrations/instagram/@types/conversationMessages.tsbackend/plugins/frontline_api/src/modules/integrations/instagram/@types/logs.tsbackend/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
interfaceovertypealigns with coding guidelines, and extending mongoose'sDocumentfor the document interface is the correct pattern. The explicit_id: stringoverride 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
ILogDocumentinterface correctly extends bothILogand mongoose'sDocument, 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: numberis intentional for persistent menus.Mongoose subdocument
_idfields are typicallyObjectIdorstring. Usingnumberhere 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 standardstringtype.
9-25: LGTM!The
IBotandIBotDocumentinterfaces 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
Documenttype.backend/plugins/frontline_api/src/modules/knowledgebase/db/definitions/article.ts (3)
5-11: LGTM!The internal
formcodesSchemais well-defined with_id: falseto avoid unnecessary subdocument IDs.
13-57: Schema structure looks good overall.The article schema is well-designed with:
- Proper use of
mongooseStringRandomIdfor_id- Required fields for
content,status, andtitle- Sensible defaults for
status,isPrivate,reactionChoices, andviewCount- Timestamps enabled
59-59: Sparse unique index is appropriate for optionalcodefield.The index correctly allows multiple documents with
code: null/undefinedwhile 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
mongooseStringRandomIdfor_id- Required
titlefield- Correctly typed
categoryIdsas string array- Timestamps enabled
- Appropriate sparse unique index on
codebackend/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
Documenttype, 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
ICustomerinterface are well-defined. Using an interface aligns with coding guidelines, and the optionalerxesApiIdappropriately reflects that this external ID may not exist at creation time.
13-15: LGTM!The
ICustomerDocumentcorrectly extends bothICustomerand Mongoose'sDocument. Explicitly declaring_id: stringis appropriate for working with stringified ObjectIds in application code.backend/plugins/frontline_api/src/modules/integrations/instagram/@types/utils.ts (1)
27-29: Unused_cacheKeyparameter and incomplete hook implementation.The
_cacheKeyparameter is accepted but never used, and the function name suggests hook functionality that isn't implemented—it just delegates toschemaWrapper. Is this a placeholder for future functionality, or should the parameter be removed?Additionally, add type annotation for the
schemaparameter 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
Documentis appropriate for extending document interfaces.
3-15: Remove the suggestion to renamecomment_id—it maps directly to external API responses.The
comment_idfield is intentionally named in snake_case because it directly corresponds to the Facebook and Instagram API response format. Renaming it tocommentIdwould 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?: anycould 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: truedisables 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; |
There was a problem hiding this comment.
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.
| 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; |
There was a problem hiding this comment.
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.
| 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.
| 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; | ||
| }; |
There was a problem hiding this comment.
🛠️ 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).
| 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; | ||
| }, |
There was a problem hiding this comment.
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.
| 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.
There was a problem hiding this comment.
Caution
Changes requested ❌
Reviewed efe8ef3 in 3 minutes and 3 seconds. Click for details.
- Reviewed
1822lines of code in34files - Skipped
0files when reviewing. - Skipped posting
11draft 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 hasisBackBtn: truein the payload. The regular menu items use_idfrom the database (line 221), but the back button doesn't have a real database ID since it's dynamically generated. ThepersistentMenuId: 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? TheisBackBtn: trueflag 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 hasisBackBtn: trueas its identifier, and thepersistentMenuIdappears 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 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(); |
There was a problem hiding this comment.
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.
| 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,`, |
There was a problem hiding this comment.
The getPostDetails request string includes a trailing comma in the fields parameter. Remove the trailing comma to ensure the query returns valid data.
| `/${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 |
There was a problem hiding this comment.
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 ( |
There was a problem hiding this comment.
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"); |
There was a problem hiding this comment.
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).
| 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"); |
There was a problem hiding this comment.
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).
| 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:'); |
There was a problem hiding this comment.
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.
| 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 ${ |
There was a problem hiding this comment.
Typo: "Error ocurred" should be "Error occurred".
| `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 ${ |
There was a problem hiding this comment.
Typo: "Error ocurred" should be "Error occurred".
| `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( |
There was a problem hiding this comment.
Typo in variable name: accounInfo is likely intended to be accountInfo. Please update for consistency (also check occurrences at lines 285 and 297).
There was a problem hiding this comment.
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 haslabel: '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:optionalis not a valid Mongoose schema option.Mongoose does not recognize
optionalas 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, userequired: true.🔧 Suggested fix
- botId: { type: String, optional: true } + botId: Stringbackend/plugins/frontline_api/src/modules/integrations/instagram/debuggers.ts-5-5 (1)
5-5: Inconsistent namespace format.Line 5 uses
erxes-integrations-crons:(hyphen beforecrons) while all other namespaces follow theerxes-integrations:*pattern with a colon separator. This inconsistency will affect filtering when enabling debug output via theDEBUGenvironment 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:optionalis not recognized.Both
customerIdanduserIduseoptional: 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:optionalis not recognized.Mongoose schemas use
required: true/false, notoptional. Theoptional: trueproperty will be silently ignored. Since fields are optional by default in Mongoose, you can simply remove this property or userequired: falseexplicitly 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:optionalis not recognized.Same issue as in postConversations.ts. Mongoose uses
required, notoptional.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: UseschemaWrapperfor consistency with other Instagram schemas and add theprocessIdfield.Most Instagram db/definitions modules use
schemaWrapperfrom erxes-api-shared. This file should follow the same pattern. TheschemaWrapperutility adds aprocessIdfield and ensures consistent schema structure across the module.Additionally, since
integrationIdanderxesApiIdare 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, andIMessageData.message.attachmentsrepresent attachments in three different contexts: flat input format, API request wrapper format, and generic incoming message payload. While thegenerateAttachmentMessagesfunction correctly transformsIAttachment[]intoIAttachmentMessage[]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 thatIAttachmentis the input format,IAttachmentMessageis the API message wrapper, andIMessageData.message.attachmentsis for incoming messages.backend/plugins/frontline_api/src/modules/knowledgebase/graphql/resolvers/customResolvers/category.ts-6-21 (1)
6-21: Type mismatch:query.statuschanges from object to string.The
query.statusis initially typed as{ $in: string[] }but gets reassigned tostatus(a string) on line 15. This causes a type inconsistency. Additionally,argslacks 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.
refreshPageAccesTokenshould berefreshPageAccessToken(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: Replaceconsole.errorwith debug utility.Line 190 uses
console.errorwhich violates the coding guideline "Avoid console logs". Use the existingdebugErrorutility 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.
fetchPagesPostsListandfetchPagePostsaccessresponse.datawithout first checking ifresponseis defined, unlikefetchPagePostwhich 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: trueis not valid Mongoose schema syntax.Mongoose uses
required: true/false, notoptional. Fields are optional by default, so you can simply removeoptional: trueor userequired: falseif 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:valuetyped asstring[]but schema defines it asObject.The
createOrUpdateConfigmethod typesvalueasstring[], but the config schema definesvalueas{ 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 usingMath.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: DeriveALLfrom the defined constants to avoid duplication.The
ALLarray duplicates the string literals instead of referencing the constants. If a value changes (e.g.,ERROR: 'err'), theALLarray 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
ALLwithin 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
ALLarray duplicates literal strings. Additionally, note the order mismatch: constants are declaredMESSENGERthenPOST, butALLlists'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 addingas constfor better type inference.The array is fine, but adding
as constwould 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 forcreatedAt.The
createdAtfield 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
mongooseStringRandomIdandschemaWrapperare imported fromerxes-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 justconversationIdorcustomerIdrespectively (index prefix property). The individualindex: trueon 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 forselectorparameter.Using
anyfor the selector parameter loses type safety. Consider using Mongoose'sFilterQuerytype 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 forselectorparameter.Same suggestion as for
Comment_conversations.ts- usingFilterQuery<IInstagramCommentConversationReplyDocument>would improve type safety.backend/plugins/frontline_api/src/modules/integrations/instagram/types.ts (1)
9-11: Avoid usinganytype — 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 importdebugExternalRequests.
debugExternalRequestsis imported but never used in this file.Suggested fix
-import { debugBase, debugExternalRequests } from './debuggers'; +import { debugBase } from './debuggers';
11-35: Remove unusedIRequestParamsinterface.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 forcodeanddefaultValueparameters.Per coding guidelines, TypeScript should be used with explicit types. The
codeanddefaultValueparameters are implicitly typed asany.Suggested fix
-export const getConfig = async (models: IModels, code, defaultValue?) => { +export const getConfig = async (models: IModels, code: string, defaultValue?: string) => {
123-125: Consider usingredis.del()for cache invalidation.Setting the cache to an empty string works due to the falsy check in
getConfigs, but usingredis.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 forconfigsMapbased on the config model structure whereconfig.valueis 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
createdByauthor, 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
pageIdandpageTokenparameters 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
unsubscribePageat lines 217-220.
240-242: Redundant try-catch block.Same issue as
getFacebookPageIdsForInsta- the catch block simply rethrows without adding value.
279-288: Unnecessaryawaiton synchronous function.
getPageAccessTokenFromMapis a synchronous function that returns a string directly. Theawaiton 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:
Missing timestamps: Unlike
configSchema, this schema doesn't enabletimestamps: true. Consider adding for consistency and audit trail.
expirationas String: If this represents token expiration time, aDatetype would enable proper comparison and TTL operations.Indexes: Fields like
accountId,erxesApiId, andinstagramPageIdmay 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, Documentwhileaccounts.tsuses the modernHydratedDocument<T>pattern. For consistency across the Instagram types and better type inference with Mongoose 8.x, consider aligning toHydratedDocument.♻️ 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 thananyforvalue.Per coding guidelines favoring TypeScript best practices,
value: anyloses type safety. If the config value structure is known, consider using a more specific type orunknownto 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()whileconfigs.tsandintegrations.tsexport rawSchemainstances. 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 forselectorparameter.The
selectorparameter 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 forselectorparameter.The
selectorparameter 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 forconfigsMapparameter.The
configsMapparameter 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 exportingIPersistentMenusand review the_idtype.
IPersistentMenusis not exported but may be needed by consumers that work with persistent menus. Also,_id: numberis unusual for document identifiers—typicallystringor Mongoose'sObjectIdis 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 importgetPageAccessTokenInstagram.
getPageAccessTokenInstagramis imported but never used in this file.♻️ Remove unused import
import { getPageAccessToken, - graphRequest, - getPageAccessTokenInstagram + graphRequest } from '@/integrations/instagram/utils';
12-33: Add type annotation fordocparameter.The
docparameter is typed asany, which loses type safety. Consider usingPartial<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_idparameter.Missing type annotation on the
_idparameter. 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.
- The
docparameter lacks a type annotation.- 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
📒 Files selected for processing (34)
backend/plugins/frontline_api/src/apollo/resolvers/mutations.tsbackend/plugins/frontline_api/src/connectionResolvers.tsbackend/plugins/frontline_api/src/modules/integrations/facebook/db/definitions/comment_conversations_reply.tsbackend/plugins/frontline_api/src/modules/integrations/instagram/@types/accounts.tsbackend/plugins/frontline_api/src/modules/integrations/instagram/@types/bots.tsbackend/plugins/frontline_api/src/modules/integrations/instagram/@types/comment_conversations.tsbackend/plugins/frontline_api/src/modules/integrations/instagram/@types/comment_conversations_reply.tsbackend/plugins/frontline_api/src/modules/integrations/instagram/@types/configs.tsbackend/plugins/frontline_api/src/modules/integrations/instagram/@types/integrations.tsbackend/plugins/frontline_api/src/modules/integrations/instagram/commonUtils.tsbackend/plugins/frontline_api/src/modules/integrations/instagram/constants.tsbackend/plugins/frontline_api/src/modules/integrations/instagram/db/definitions/accounts.tsbackend/plugins/frontline_api/src/modules/integrations/instagram/db/definitions/bots.tsbackend/plugins/frontline_api/src/modules/integrations/instagram/db/definitions/comment_conversations.tsbackend/plugins/frontline_api/src/modules/integrations/instagram/db/definitions/comment_conversations_reply.tsbackend/plugins/frontline_api/src/modules/integrations/instagram/db/definitions/configs.tsbackend/plugins/frontline_api/src/modules/integrations/instagram/db/definitions/conversationMessages.tsbackend/plugins/frontline_api/src/modules/integrations/instagram/db/definitions/conversations.tsbackend/plugins/frontline_api/src/modules/integrations/instagram/db/definitions/customers.tsbackend/plugins/frontline_api/src/modules/integrations/instagram/db/definitions/integrations.tsbackend/plugins/frontline_api/src/modules/integrations/instagram/db/definitions/logs.tsbackend/plugins/frontline_api/src/modules/integrations/instagram/db/definitions/postConversations.tsbackend/plugins/frontline_api/src/modules/integrations/instagram/db/models/Accounts.tsbackend/plugins/frontline_api/src/modules/integrations/instagram/db/models/Bots.tsbackend/plugins/frontline_api/src/modules/integrations/instagram/db/models/Comment_conversations.tsbackend/plugins/frontline_api/src/modules/integrations/instagram/db/models/Comment_conversations_reply.tsbackend/plugins/frontline_api/src/modules/integrations/instagram/db/models/Configs.tsbackend/plugins/frontline_api/src/modules/integrations/instagram/db/models/Integrations.tsbackend/plugins/frontline_api/src/modules/integrations/instagram/debuggers.tsbackend/plugins/frontline_api/src/modules/integrations/instagram/types.tsbackend/plugins/frontline_api/src/modules/integrations/instagram/utils.tsbackend/plugins/frontline_api/src/modules/knowledgebase/graphql/resolvers/customResolvers/category.tsbackend/plugins/frontline_api/src/modules/knowledgebase/graphql/resolvers/customResolvers/topic.tsbackend/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.tsbackend/plugins/frontline_api/src/modules/integrations/instagram/db/definitions/configs.tsbackend/plugins/frontline_api/src/modules/integrations/instagram/@types/configs.tsbackend/plugins/frontline_api/src/modules/integrations/instagram/db/definitions/comment_conversations.tsbackend/plugins/frontline_api/src/modules/integrations/instagram/db/definitions/comment_conversations_reply.tsbackend/plugins/frontline_api/src/modules/integrations/instagram/db/definitions/integrations.tsbackend/plugins/frontline_api/src/modules/integrations/instagram/types.tsbackend/plugins/frontline_api/src/modules/integrations/instagram/db/definitions/accounts.tsbackend/plugins/frontline_api/src/modules/integrations/instagram/db/definitions/postConversations.tsbackend/plugins/frontline_api/src/modules/integrations/instagram/db/definitions/bots.tsbackend/plugins/frontline_api/src/modules/integrations/instagram/@types/accounts.tsbackend/plugins/frontline_api/src/modules/integrations/instagram/constants.tsbackend/plugins/frontline_api/src/modules/integrations/instagram/db/definitions/logs.tsbackend/plugins/frontline_api/src/modules/integrations/instagram/@types/integrations.tsbackend/plugins/frontline_api/src/modules/integrations/instagram/db/models/Comment_conversations.tsbackend/plugins/frontline_api/src/modules/integrations/instagram/db/models/Comment_conversations_reply.tsbackend/plugins/frontline_api/src/modules/integrations/instagram/db/definitions/conversationMessages.tsbackend/plugins/frontline_api/src/modules/knowledgebase/graphql/resolvers/customResolvers/category.tsbackend/plugins/frontline_api/src/modules/integrations/instagram/commonUtils.tsbackend/plugins/frontline_api/src/modules/integrations/instagram/db/models/Configs.tsbackend/plugins/frontline_api/src/modules/integrations/instagram/db/models/Accounts.tsbackend/plugins/frontline_api/src/modules/integrations/instagram/utils.tsbackend/plugins/frontline_api/src/modules/integrations/instagram/db/models/Bots.tsbackend/plugins/frontline_api/src/modules/integrations/instagram/@types/bots.tsbackend/plugins/frontline_api/src/modules/integrations/instagram/db/models/Integrations.tsbackend/plugins/frontline_api/src/modules/integrations/instagram/db/definitions/customers.tsbackend/plugins/frontline_api/src/modules/integrations/instagram/debuggers.tsbackend/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)
| export interface IInstagramAccount { | ||
| kind: string; | ||
| token: string; | ||
| username?: string; | ||
| email: string; | ||
| tokenSecret?: string; | ||
| expireDate?: string; | ||
| scope?: string; | ||
| name: string; | ||
| uid: string; | ||
| } |
There was a problem hiding this comment.
🧩 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 fRepository: 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.tsRepository: 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.tsRepository: 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.
| tokenSecret: { | ||
| type: String, | ||
| optional: true | ||
| }, | ||
| scope: { | ||
| type: String, | ||
| optional: true | ||
| }, | ||
| expireDate: { | ||
| type: String, | ||
| optional: true | ||
| }, |
There was a problem hiding this comment.
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.
| 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() }, |
There was a problem hiding this comment.
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.
| 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.
| 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], | ||
| }) |
There was a problem hiding this comment.
🧩 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 dRepository: 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.tsRepository: 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.tsRepository: 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.tsRepository: 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.
| 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" }; | ||
| } |
There was a problem hiding this comment.
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.
| 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.
| 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}` | ||
| ); |
There was a problem hiding this comment.
🛠️ 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.
| 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; | ||
| }; |
There was a problem hiding this comment.
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.
| 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.
| 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); | ||
| } | ||
| }; |
There was a problem hiding this comment.
🧩 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
- Meta / coverage of Graph API v19.0 release (introducing v19.0).
- CData / Datavirtuality notices referencing deprecation (deprecation commence Feb 4, 2025).
- 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.tsRepository: 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 2Repository: 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 -20Repository: 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.
| 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); | ||
| } | ||
| }; |
There was a problem hiding this comment.
🛠️ 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.
| export const KnowledgeBaseParentCategory = { | ||
| ...KnowledgeBaseCategory, | ||
|
|
||
| async childrens(category: ICategoryDocument, _args, { models }: IContext) { | ||
| return models.Category.find({ | ||
| parentCategoryId: category._id, | ||
| }).sort({ title: 1 }); | ||
| }, |
There was a problem hiding this comment.
🧩 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 -50Repository: 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 -20Repository: 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 -30Repository: 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.tsRepository: 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 -A1Repository: 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 gqlRepository: 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:
- GraphQL schema field (knowledgeBaseTypeDefs.ts line 97)
- 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.
| 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.
efe8ef3 to
dab440f
Compare
|
There was a problem hiding this comment.
Important
Looks good to me! 👍
Reviewed dab440f in 1 minute and 39 seconds. Click for details.
- Reviewed
317lines of code in13files - Skipped
0files when reviewing. - Skipped posting
15draft 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%<= threshold50%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%<= threshold50%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%<= threshold50%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%<= threshold50%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%<= threshold50%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%<= threshold50%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%<= threshold50%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%<= threshold50%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%<= threshold50%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%<= threshold50%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%<= threshold50%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%<= threshold50%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%<= threshold50%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%<= threshold50%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%<= threshold50%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 by changing your verbosity settings, reacting with 👍 or 👎, replying to comments, or adding code review rules.
There was a problem hiding this comment.
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 tofindDetailhelper.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
📒 Files selected for processing (4)
backend/plugins/frontline_api/src/apollo/resolvers/mutations.tsbackend/plugins/frontline_api/src/modules/knowledgebase/graphql/resolvers/customResolvers/category.tsbackend/plugins/frontline_api/src/modules/knowledgebase/graphql/resolvers/customResolvers/topic.tsbackend/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.tsbackend/plugins/frontline_api/src/modules/knowledgebase/graphql/resolvers/customResolvers/category.tsbackend/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 forknowledgeBaseArticlesresolver logic.The topic-to-category resolution, dynamic sorting, and pagination are correctly implemented. Good use of
defaultPaginateconsistent with codebase patterns.
90-96: LGTM!
knowledgeBaseArticleDetailcorrectly delegates tofindDetailwith fallback to code lookup.
98-108: Race condition on concurrent view count increments.While MongoDB's
$incis 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
__resolveReferenceresolver correctly implements federation reference resolution by fetching the topic by_id.
9-16: LGTM!The
brandresolver correctly returns a federation reference object whenbrandIdexists, using short-circuit evaluation.
19-23: LGTM!The
categoriesresolver correctly fetches related categories sorted by title, consistent with the pattern inknowledgeBaseQueries.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
colorfield.backend/plugins/frontline_api/src/modules/knowledgebase/graphql/resolvers/customResolvers/category.ts (3)
6-21: LGTM!The
articlesresolver 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
numOfArticlesresolver correctly counts articles with consistent status filtering logic.
| async childrens(category: ICategoryDocument, _args, { models }: IContext) { | ||
| return models.Category.find({ | ||
| parentCategoryId: category._id, | ||
| }).sort({ title: 1 }); | ||
| }, |
There was a problem hiding this comment.
🧩 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 -20Repository: 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 tsRepository: 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 tsRepository: 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 tsRepository: 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 tsxRepository: 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-listRepository: erxes/erxes
Length of output: 444
🏁 Script executed:
#!/bin/bash
# Search more broadly for childrens in all files
rg -n "childrens" --no-require-gitRepository: 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 -iRepository: 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.
| 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`.
| keys.forEach((key) => { | ||
| if (args[key] && args[key].length > 0) { | ||
| const field = key.replace('s', ''); | ||
| qry[field] = { $in: args[key] }; | ||
| } |
There was a problem hiding this comment.
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.
| 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.
| 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' } }, | ||
| ]; | ||
| } |
There was a problem hiding this comment.
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.
| async knowledgeBaseTopicsTotalCount( | ||
| _root, | ||
| _args, | ||
| { models }: IContext | ||
| ) { | ||
| return models.Topic.countDocuments({}); | ||
| } |
There was a problem hiding this comment.
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.
Important
Integrates a comprehensive knowledge base system with articles, categories, and topics into the existing codebase, including models, GraphQL schemas, queries, and mutations.
KnowledgeBaseArticle,KnowledgeBaseCategory, andKnowledgeBaseTopicmodels with CRUD operations indb/models/Article.ts,db/models/Category.ts, anddb/models/Topic.ts.graphql/schemas/knowledgeBaseTypeDefs.ts,graphql/resolvers/queries/knowledgeBaseQueries.ts, andgraphql/resolvers/mutations/knowledgeBaseMutations.ts.graphql/resolvers/customResolvers/article.ts,category.ts, andtopic.ts.schema.ts,mutations.ts,queries.ts, andresolvers.tsto include knowledge base entities.typeDefs.tsto integrate new types, queries, and mutations.db/definitions/article.ts,category.ts, andtopic.ts.db/utils.tsfor schema field handling.db/definitions/constant.tsand module names inutils/constants.ts.This description was created by
for dab440f. You can customize this summary. It will automatically update as commits are pushed.
Summary by CodeRabbit
New Features
Chores
✏️ Tip: You can customize this high-level summary in your review settings.