Feat/reviews - #437
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Warning Review limit reached
More reviews will be available in 47 minutes and 26 seconds. Learn how PR review limits work. Your organization has run out of usage credits. Purchase more in the billing tab. ⌛ How to resolve this issue?After more reviews become available, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available. Please see our Fair Usage Limits Policy for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (7)
WalkthroughAdds a full product review feature set: DB models and migrations, admin and store APIs with validators and normalisers, React admin list/detail UI, workflows for creating/updating reviews and sending review-request emails, a persistent workflow queue and runner, Herbatica XML parsing utilities and a reviews import seed, plus config and middleware wiring. ChangesProduct Review Core & Admin Management
Store Reviews API
Review Request Workflow & Workflow Queue System
Supporting Features & Configuration
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
✨ Finishing Touches🧪 Generate unit tests (beta)
✨ Simplify code
|
Greptile SummaryThis PR introduces a full product review system: customers can submit reviews (authenticated or via single-use email tokens), admins can manage and bulk-update them, and review-request emails are scheduled automatically after payment via a new workflow-queue mechanism. An XML import script for seeding Herbatica reviews is also included.
Confidence Score: 4/5Safe to merge with one data integrity fix recommended before the feature is live for customers who may check out as guests and later authenticate. The guest-token synthetic customer ID (review-token:{id}) differs from the real customer ID on authenticated paths, so the duplicate-review guard in ensureReviewDoesNotExist cannot cross-reference the two submission modes. A customer who submitted via a guest token and later authenticates can submit a second review for the same product. Everything else — token expiry, batch limits, locking, normalizers — looks correct. apps/medusa-be/src/api/store/reviews/helpers.ts (getReviewTokenCustomerId and ensureReviewDoesNotExist interaction) and apps/medusa-be/src/api/store/reviews/route.ts (submission path that merges token and auth contexts). Important Files Changed
Reviews (5): Last reviewed commit: "fix: remove review summary batch setting" | Re-trigger Greptile |
There was a problem hiding this comment.
Actionable comments posted: 25
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
apps/medusa-be/src/modules/resend/service.ts (1)
159-171:⚠️ Potential issue | 🟠 Major | ⚡ Quick winValidate template variable values before type casting.
The template variable values are cast to
TemplateVariableValuewithout validation on lines 160 and 170. Whilst the expanded type definition now supports complex nested structures (arrays, objects, primitives), the casting should be preceded by validation to ensure the data conforms to the expected shape. As per coding guidelines, you must validate data before type casting.🛡️ Proposed fix to add validation
+function isTemplateVariableValue(value: unknown): value is TemplateVariableValue { + if (value === null || typeof value === "boolean" || typeof value === "number" || typeof value === "string") { + return true + } + if (Array.isArray(value)) { + return value.every(isTemplateVariableValue) + } + if (typeof value === "object" && value !== null) { + return Object.values(value).every(isTemplateVariableValue) + } + return false +} + protected getTemplateVariables( definition: ResendTemplateDefinition, data?: Record<string, unknown> | null ) { const variables: Record<string, TemplateVariableValue> = {} const missingVariables: string[] = [] for (const variable of definition.requiredVariables) { const value = data?.[variable] - if (value !== undefined && value !== null) { - variables[variable] = value as TemplateVariableValue + if (value !== undefined && value !== null && isTemplateVariableValue(value)) { + variables[variable] = value } else { missingVariables.push(variable) } } for (const variable of definition.optionalVariables) { const value = data?.[variable] variables[variable] = - value !== undefined && value !== null - ? (value as TemplateVariableValue) + value !== undefined && value !== null && isTemplateVariableValue(value) + ? value : "" }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/medusa-be/src/modules/resend/service.ts` around lines 159 - 171, The code currently assigns data values into variables[] by blind casting to TemplateVariableValue in the block handling required variables (uses missingVariables and variables) and optionalVariables; add a validation step before casting: for each variable in definition.variables and definition.optionalVariables, validate that data?.[variable] conforms to acceptable TemplateVariableValue shapes (primitive types string|number|boolean, arrays, or plain objects with serializable values) and only then assign (variables[variable] = value as TemplateVariableValue); if validation fails treat it as missing (push to missingVariables for required ones) or set optional to ""/skip assignment; implement a reusable helper validateTemplateVariable(value): boolean and use it in both the required-variable loop and the optional-variable loop to avoid duplicate logic and ensure safe casting.Source: Coding guidelines
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@apps/medusa-be/src/admin/lib/reviews.ts`:
- Around line 34-41: The ReviewInput type currently requires all fields but
AdminUpdateReviewSchema defines them as optional for partial updates; change the
ReviewInput definition (or add a new AdminUpdateReviewInput) so all updateable
properties (content, title, rating, status, first_name, last_name) are optional
to match AdminUpdateReviewSchema in validators.ts and allow partial updates;
ensure the type used by update functions references this optional/update input
(or the new AdminUpdateReviewInput) so the runtime refinement ("at least one
field") and compile-time types align.
In `@apps/medusa-be/src/api/admin-app-static.ts`:
- Around line 26-54: The resolveAdminFile function currently checks
normalizedRelativePath for traversal but does not verify the final requestedFile
is still contained inside adminPublicDir; update resolveAdminFile to compute the
absolute/resolved paths (e.g., use path.resolve or fs.realpathSync) for
adminPublicDir and requestedFile and confirm requestedFile startsWith or is
within the resolved adminPublicDir before returning it (if containment fails,
return undefined). Ensure you reference requestedFile, adminPublicDir, and
normalizedRelativePath when adding this containment check so the final returned
path cannot escape the admin directory.
In `@apps/medusa-be/src/api/admin/reviews/`[id]/route.ts:
- Around line 16-24: The code in getNormalizedReview currently force-casts the
result of retrieveReview to ReviewRecord which skips validation; instead,
validate the object returned by req.scope.resolve(...).retrieveReview(id) before
using it—either update the service signature to return ReviewRecord or add a
runtime type guard/schema validation (for example a isReviewRecord check or
zod/io-ts schema) that verifies required fields (id, product_id, etc.) and
throws or returns a typed error if validation fails; only after passing that
guard should you pass the value to getProductsById and normalizeAdminReview, and
remove the direct "as ReviewRecord" assertion.
In `@apps/medusa-be/src/api/admin/reviews/helpers.ts`:
- Around line 5-25: getProductsById currently asserts (data as ProductRecord[])
without validation; change to validate or strongly type the response from
query.graph. Either (1) add runtime checks after the call: verify
Array.isArray(data) and that each item has the required keys (id, title, handle,
thumbnail), filter/throw if invalid, then map to new Map using the validated
array; or (2) annotate the destructured result with an explicit type like const
{ data }: { data: ProductRecord[] } = await query.graph(...) so TypeScript
enforces the shape; reference getProductsById, the query.graph call, the data
variable, and ProductRecord when making the change.
In `@apps/medusa-be/src/api/admin/reviews/route.ts`:
- Around line 23-33: The code unsafely casts the result of listAndCountReviews
to ReviewRecord[] before validating its shape; add a runtime validation/type
guard for reviews (e.g., isReviewRecordArray) immediately after calling
listAndCountReviews and before passing reviews into
getUniqueReviewProductIds/getProductsById, and handle the invalid case (throw a
clear error or return a 400/500 response) so you never use `as ReviewRecord[]`
without checking the structure; update references in the block where
listAndCountReviews, getUniqueReviewProductIds, and getProductsById are used to
rely on the validated value.
In `@apps/medusa-be/src/api/store/products/`[id]/reviews/route.ts:
- Around line 27-36: Currently the code uses service.listReviews to fetch all
approved reviews and computes ratingTotal and averageRating in-memory
(functions/vars: service.listReviews, ratingTotal, averageRating), which is
inefficient; change this to use a cached aggregate: compute the average via a DB
aggregation or a new service method (e.g., service.getAverageRating or a DB
query with AVG) and cache the result with caching.set() keyed by product id and
a tag like reviews:product:{id}; on review create/update/delete ensure the cache
is invalidated via the same tag (or call caching.del on that key) so subsequent
GETs read the cached average instead of calling listReviews and re-reducing all
rows.
- Line 42: The reviews returned from service.listAndCountReviews are being
force-cast to ReviewRecord[] and passed to normalizePublicReview; instead add a
runtime validation step: verify the service result is an array (Array.isArray)
and that each element has the expected properties (or implement a small type
guard like isReviewRecord) before mapping, and if validation fails log/error and
fall back to an empty array or reject the request; update the code around the
reviews variable (the call to service.listAndCountReviews and the subsequent
mapping to normalizePublicReview) to perform this check and avoid using "as
ReviewRecord[]" without validation.
In `@apps/medusa-be/src/api/store/reviews/helpers.ts`:
- Around line 174-193: The code casts query.graph result to ProductRecord[]
without runtime checks; update ensureProductExists to validate the response from
query.graph (the returned "data") before casting: ensure data is defined and
Array.isArray(data), that data[0] exists, and that data[0].id is a non-empty
string (or appropriate type) before using it; if validation fails, throw the
same MedusaError NOT_FOUND for ProductRecord not found. Reference:
ensureProductExists, query.graph, ProductRecord, MedusaError.
- Around line 158-172: The helper retrieveCustomer currently casts query.graph's
result to CustomerRecord[] without runtime validation; update retrieveCustomer
to treat the graph response as unknown, verify the shape (ensure the returned
object has a data property that's an array and that the first element matches
CustomerRecord fields like id, first_name, last_name) before casting, and return
undefined or throw a controlled error if validation fails. Use a small type
guard function (e.g., isCustomerRecord) and validate the response from
query.graph() prior to accessing (data as unknown) and casting to
CustomerRecord[] so you avoid unsafe type assertions.
In
`@apps/medusa-be/src/modules/product-review/migrations/Migration20260610090000.ts`:
- Line 1: The import in Migration20260610090000.ts uses "`@mikro-orm/migrations`"
but must match the earlier migration; change the import for the Migration symbol
to use "`@medusajs/framework/mikro-orm/migrations`" so the file imports Migration
from the Medusa framework wrapper (consistent with Migration20260525120000.ts);
update the single import line to reference the Medusa package and keep the
exported class/usage unchanged.
In `@apps/medusa-be/src/modules/workflow-queue/index.ts`:
- Line 4: The module key constant WORKFLOW_QUEUE_MODULE is using camelCase value
"workflowQueue" but should follow underscore naming per Medusa conventions;
update the value of WORKFLOW_QUEUE_MODULE to "workflow_queue" so the module key
uses underscores consistently throughout the config and imports that reference
WORKFLOW_QUEUE_MODULE continue to work.
In
`@apps/medusa-be/src/modules/workflow-queue/migrations/Migration20260610080000.ts`:
- Around line 8-10: Remove the redundant partial index creation in
Migration20260610080000.ts: delete the addSql call that creates
"IDX_workflow_queue_item_deleted_at" on workflow_queue_item (deleted_at) WHERE
deleted_at IS NULL; (or replace it only if you actually need to index deleted
rows by changing the predicate to WHERE deleted_at IS NOT NULL or create an
index on other queried columns). Ensure the migration no longer emits the CREATE
INDEX IF NOT EXISTS "IDX_workflow_queue_item_deleted_at" ... WHERE deleted_at IS
NULL statement.
In `@apps/medusa-be/src/scripts/herbatica-reviews-seed.ts`:
- Line 153: The loop casts `data` directly to `ProductVariantRecord[]` which
violates the guideline to validate before type casting; update the code around
the `for (const variant of data as ProductVariantRecord[])` line to first verify
`data` is an array (e.g., Array.isArray(data)) and that each element contains
the expected properties (using a small type guard function or runtime checks for
keys like id, sku, price) before treating items as ProductVariantRecord, and
only then iterate or map to a typed array for subsequent use.
- Around line 255-264: The code uses an unchecked cast "as ReviewRecord[]" on
the result of reviewService.listReviews (assigned to existingReviews); replace
the unchecked cast with runtime validation: call reviewService.listReviews and
verify the result is an array and each item matches the expected shape (e.g.,
has id, customer_id, product_id) before treating it as ReviewRecord[], or use an
existing runtime/schema validator (zod/io-ts) to parse the response; update the
logic around existingReviews to handle validation failures (throw or bail out)
rather than assuming the type.
- Around line 142-169: The resolved query instance in buildVariantProductIndexes
should use an explicit generic type: change the container.resolve call for
ContainerRegistrationKeys.QUERY to
container.resolve<Query>(ContainerRegistrationKeys.QUERY) so the variable
`query` has the Query type; ensure the Query type is imported or available in
this module and update any related usage if the explicit typing surfaces type
errors in functions like query.graph or ProductVariantRecord handling.
- Around line 290-301: The code pushes review objects with created_at/updated_at
set via new Date(review.timestamp) which can produce Invalid Date for malformed
strings; in the pendingReviews push (the object built where created_at and
updated_at are assigned), validate review.timestamp before constructing Date
(e.g., use Date.parse or isNaN check) and only set created_at/updated_at to a
new Date(...) when the timestamp is present and valid, otherwise set them to
undefined (or omit them) so no Invalid Date objects are persisted.
In `@apps/medusa-be/src/scripts/herbatica-xml-utils.ts`:
- Around line 72-84: The regex in extractElements constructs a pattern using the
raw tag parameter which can misbehave or cause ReDoS if tag contains regex
metacharacters; escape the tag before building the RegExp (e.g., implement or
reuse an escapeRegex helper that replaces special chars like . * + ? ^ $ { } ( )
| [ ] \ / with escaped versions) and use the escaped tag when creating the
RegExp in extractElements, and apply the identical escape logic to
extractFirstElementContent so both functions safely handle arbitrary tag
strings.
In
`@apps/medusa-be/src/subscriber-helpers/product-review-request-on-payment/helper.ts`:
- Around line 48-50: The current helper uses fragile ID prefix checks
(data.id?.startsWith("order_"/"paycol_"/"pay_") at the three sites referenced)
to infer entity type; change these checks to use explicit entity-type metadata
or fields (e.g., check a stable property like data.type, data.resource_type, or
an accompanying enum/value returned by Medusa) inside the same helper functions,
falling back to the legacy startsWith only if no explicit field exists while
emitting a warning; update the logic in the functions that perform the "order_",
"paycol_" and "pay_" checks (the three blocks shown) to prefer explicit type
fields and add a short comment mentioning the fallback behavior.
- Line 98: The code casts data to OrderPaymentCollectionQueryResult[] and
assigns the first element to link without validation; add a guard that checks
Array.isArray(data) and data.length > 0 and that the first element matches the
expected shape before casting/using it (e.g., verify required fields exist),
then safely assign const link = data[0] as OrderPaymentCollectionQueryResult or
handle the missing/invalid case by returning early or throwing/logging an error;
update the assignment site (the variable link) to use this validated value so
downstream code cannot assume a valid result.
- Around line 109-110: The code casts data to PaymentQueryResult[] and reads
payment_collection_id without validating the query result; update the helper to
first check that data is an array and has at least one element and that the
first element contains a defined payment_collection_id before using it (i.e.,
validate typeof/Array.isArray(data) and the presence of (data as
any)[0].payment_collection_id), and only then assign paymentCollectionId (or
handle the missing/invalid case by returning early or throwing); reference the
variables paymentCollectionId, data and the PaymentQueryResult type in your
changes.
In `@apps/medusa-be/src/utils/order-review-requests.ts`:
- Around line 176-178: The getReviewRequestMessage function currently returns a
hardcoded Czech string; change it to read from the app's i18n/translation system
instead (e.g., call a translate/i18n function or load from a translations
object) and support locale selection by accepting a locale or context parameter
if needed; update getReviewRequestMessage to return the translated key (for
example "review.request_message") via the existing translation helper (or add
one) so the message is not hardcoded and can be localized.
- Line 154: The code casts the result of query.graph to ReviewRequestOrder[]
without runtime validation; update the handling around the query.graph call to
validate that data is an array and that each element matches the expected
ReviewRequestOrder shape before assigning to orders (e.g., use
Array.isArray(data) and check required fields or a runtime validator like zod),
and if validation fails, log or throw a clear error and return/handle a safe
fallback instead of blindly doing const orders = data as ReviewRequestOrder[];
refer to the variables/data returned from query.graph, the orders variable, and
the ReviewRequestOrder type when implementing the checks.
In `@apps/medusa-be/src/utils/product-review-request-queue.ts`:
- Line 73: The code currently force-casts the query result with (data as
ReviewRequestOrder[])[0] without validation; change this to validate data before
casting by: check Array.isArray(data) and data.length>0, then either verify the
first element with a type guard (e.g., isReviewRequestOrder(obj) that checks
required properties) or use a runtime schema validator, and only then return the
first element; if validation fails, return null or throw a descriptive error.
Ensure you add a small type guard function isReviewRequestOrder(obj: any): obj
is ReviewRequestOrder and use it at the return site instead of the direct cast
so the function safely handles unexpected query shapes.
In `@apps/medusa-be/src/utils/workflow-queue-registry.ts`:
- Around line 27-31: Replace the generic throw with a MedusaError of type
INVALID_DATA: change the throw in the validation branch that uses
isSendProductReviewRequestWorkflowInput to throw new
MedusaError(MedusaError.Types.INVALID_DATA, `Invalid arguments for
${workflowQueueNames.SEND_PRODUCT_REVIEW_REQUEST}`) and add the MedusaError
import (e.g. import { MedusaError } from "medusa-core-utils") at the top of the
file so the function uses MedusaError for validation failures.
In `@apps/medusa-be/src/workflows/send-product-review-request.ts`:
- Line 225: The code directly casts the query result into
ReviewRequestOrderWithItems[] when assigning to the variable order; instead,
first validate that data is an array and contains the expected item(s) (e.g.,
Array.isArray(data) && data.length > 0) and optionally that required fields
exist on the first element, then safely assign or narrow the type before using
it. Update the assignment around the variable order in
send-product-review-request (where const order = (data as
ReviewRequestOrderWithItems[])[0]) to check the shape and handle the
empty/invalid case (return early, throw a clear error, or fallback) rather than
unguarded type assertion.
---
Outside diff comments:
In `@apps/medusa-be/src/modules/resend/service.ts`:
- Around line 159-171: The code currently assigns data values into variables[]
by blind casting to TemplateVariableValue in the block handling required
variables (uses missingVariables and variables) and optionalVariables; add a
validation step before casting: for each variable in definition.variables and
definition.optionalVariables, validate that data?.[variable] conforms to
acceptable TemplateVariableValue shapes (primitive types string|number|boolean,
arrays, or plain objects with serializable values) and only then assign
(variables[variable] = value as TemplateVariableValue); if validation fails
treat it as missing (push to missingVariables for required ones) or set optional
to ""/skip assignment; implement a reusable helper
validateTemplateVariable(value): boolean and use it in both the
required-variable loop and the optional-variable loop to avoid duplicate logic
and ensure safe casting.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 94439d1e-eba0-4730-b4d7-4392a78f64eb
📒 Files selected for processing (54)
.env.dockerapps/medusa-be/medusa-config.tsapps/medusa-be/package.jsonapps/medusa-be/src/admin/lib/reviews.tsapps/medusa-be/src/admin/routes/reviews/[id]/page.tsxapps/medusa-be/src/admin/routes/reviews/page.tsxapps/medusa-be/src/api/admin-app-static.tsapps/medusa-be/src/api/admin/reviews/[id]/route.tsapps/medusa-be/src/api/admin/reviews/helpers.tsapps/medusa-be/src/api/admin/reviews/middlewares.tsapps/medusa-be/src/api/admin/reviews/route.tsapps/medusa-be/src/api/admin/reviews/status/route.tsapps/medusa-be/src/api/admin/reviews/validators.tsapps/medusa-be/src/api/middlewares.tsapps/medusa-be/src/api/review-normalizers.tsapps/medusa-be/src/api/store/products/[id]/reviews/route.tsapps/medusa-be/src/api/store/products/[id]/reviews/validators.tsapps/medusa-be/src/api/store/reviews/helpers.tsapps/medusa-be/src/api/store/reviews/middlewares.tsapps/medusa-be/src/api/store/reviews/route.tsapps/medusa-be/src/api/store/reviews/validators.tsapps/medusa-be/src/jobs/workflow-queue-runner.tsapps/medusa-be/src/links/customer-review.tsapps/medusa-be/src/links/product-review.tsapps/medusa-be/src/modules/product-review/index.tsapps/medusa-be/src/modules/product-review/migrations/.snapshot-product-review.jsonapps/medusa-be/src/modules/product-review/migrations/Migration20260525120000.tsapps/medusa-be/src/modules/product-review/migrations/Migration20260610090000.tsapps/medusa-be/src/modules/product-review/models/review-token.tsapps/medusa-be/src/modules/product-review/models/review.tsapps/medusa-be/src/modules/product-review/service.tsapps/medusa-be/src/modules/resend/service.tsapps/medusa-be/src/modules/resend/templates.tsapps/medusa-be/src/modules/workflow-queue/index.tsapps/medusa-be/src/modules/workflow-queue/migrations/Migration20260610080000.tsapps/medusa-be/src/modules/workflow-queue/models/workflow-queue-item.tsapps/medusa-be/src/modules/workflow-queue/service.tsapps/medusa-be/src/scripts/herbatica-category-export.tsapps/medusa-be/src/scripts/herbatica-reviews-seed.tsapps/medusa-be/src/scripts/herbatica-seed-config.tsapps/medusa-be/src/scripts/herbatica-seed.tsapps/medusa-be/src/scripts/herbatica-xml-utils.tsapps/medusa-be/src/subscriber-helpers/product-review-request-on-payment/helper.tsapps/medusa-be/src/subscribers/product-review-request-on-payment.tsapps/medusa-be/src/utils/order-review-requests.tsapps/medusa-be/src/utils/product-review-request-queue.tsapps/medusa-be/src/utils/workflow-queue-registry.tsapps/medusa-be/src/workflows/product-review/steps/create-review.tsapps/medusa-be/src/workflows/product-review/steps/mark-review-token-used.tsapps/medusa-be/src/workflows/product-review/types.tsapps/medusa-be/src/workflows/product-review/workflows/create-review.tsapps/medusa-be/src/workflows/send-product-review-request.tsapps/medusa-be/src/workflows/workflow-queue/steps/delete-workflow-queue-item.tsdocker-compose.yaml
📜 Review details
⏰ 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). (4)
- GitHub Check: Greptile Review
- GitHub Check: main
- GitHub Check: Analyze (javascript-typescript)
- GitHub Check: Kilo Code Review
🧰 Additional context used
📓 Path-based instructions (28)
apps/medusa-be/src/modules/**/*
📄 CodeRabbit inference engine (CLAUDE.md)
Place custom Medusa modules under apps/medusa-be/src/modules
Module directories use hyphens (
my-module/), but module keys in config use underscores (my_module)
Files:
apps/medusa-be/src/modules/product-review/index.tsapps/medusa-be/src/modules/workflow-queue/index.tsapps/medusa-be/src/modules/product-review/migrations/Migration20260610090000.tsapps/medusa-be/src/modules/workflow-queue/migrations/Migration20260610080000.tsapps/medusa-be/src/modules/product-review/models/review-token.tsapps/medusa-be/src/modules/product-review/migrations/Migration20260525120000.tsapps/medusa-be/src/modules/product-review/models/review.tsapps/medusa-be/src/modules/workflow-queue/models/workflow-queue-item.tsapps/medusa-be/src/modules/workflow-queue/service.tsapps/medusa-be/src/modules/product-review/service.tsapps/medusa-be/src/modules/resend/templates.tsapps/medusa-be/src/modules/resend/service.ts
apps/medusa-be/**/*.{ts,tsx}
📄 CodeRabbit inference engine (apps/medusa-be/CLAUDE.md)
apps/medusa-be/**/*.{ts,tsx}: Runnpx tsc --noEmitfor typechecking before committing
Always use braces around conditional blocks, even for single statements; Biome will expand them
Declare one variable perconst/letstatement, not multiple on one line
Use nullish coalescing operator (??) instead of logical OR (||) for default values
Do not use non-null assertions (!); use type guards or validation instead
Annotate type asunknownwhen accessing dynamic object properties before applying type guards
Use comments only to explain 'why', never 'what'; self-document code with clear naming
Extract pure functions to separate files for testability without runtime dependencies
UseModules.*andContainerRegistrationKeys.*constants instead of hardcoding module/key strings
Do not use non-null assertions in TypeScript code; validate or use type guards instead
Validate data before type casting; never useas Typewithout prior validation
Files:
apps/medusa-be/src/modules/product-review/index.tsapps/medusa-be/src/modules/workflow-queue/index.tsapps/medusa-be/src/links/customer-review.tsapps/medusa-be/src/api/store/reviews/middlewares.tsapps/medusa-be/src/links/product-review.tsapps/medusa-be/src/workflows/product-review/steps/create-review.tsapps/medusa-be/src/modules/product-review/migrations/Migration20260610090000.tsapps/medusa-be/src/modules/workflow-queue/migrations/Migration20260610080000.tsapps/medusa-be/src/modules/product-review/models/review-token.tsapps/medusa-be/src/modules/product-review/migrations/Migration20260525120000.tsapps/medusa-be/src/workflows/workflow-queue/steps/delete-workflow-queue-item.tsapps/medusa-be/src/workflows/product-review/types.tsapps/medusa-be/src/modules/product-review/models/review.tsapps/medusa-be/src/workflows/product-review/steps/mark-review-token-used.tsapps/medusa-be/src/api/store/products/[id]/reviews/validators.tsapps/medusa-be/src/modules/workflow-queue/models/workflow-queue-item.tsapps/medusa-be/src/api/admin-app-static.tsapps/medusa-be/src/workflows/send-product-review-request.tsapps/medusa-be/src/modules/workflow-queue/service.tsapps/medusa-be/src/api/store/reviews/validators.tsapps/medusa-be/src/workflows/product-review/workflows/create-review.tsapps/medusa-be/src/scripts/herbatica-seed-config.tsapps/medusa-be/src/api/admin/reviews/status/route.tsapps/medusa-be/src/api/admin/reviews/route.tsapps/medusa-be/medusa-config.tsapps/medusa-be/src/api/admin/reviews/helpers.tsapps/medusa-be/src/modules/product-review/service.tsapps/medusa-be/src/modules/resend/templates.tsapps/medusa-be/src/api/admin/reviews/validators.tsapps/medusa-be/src/api/admin/reviews/middlewares.tsapps/medusa-be/src/api/middlewares.tsapps/medusa-be/src/api/admin/reviews/[id]/route.tsapps/medusa-be/src/api/store/products/[id]/reviews/route.tsapps/medusa-be/src/api/store/reviews/route.tsapps/medusa-be/src/utils/workflow-queue-registry.tsapps/medusa-be/src/jobs/workflow-queue-runner.tsapps/medusa-be/src/subscribers/product-review-request-on-payment.tsapps/medusa-be/src/utils/product-review-request-queue.tsapps/medusa-be/src/admin/routes/reviews/[id]/page.tsxapps/medusa-be/src/admin/lib/reviews.tsapps/medusa-be/src/api/review-normalizers.tsapps/medusa-be/src/modules/resend/service.tsapps/medusa-be/src/admin/routes/reviews/page.tsxapps/medusa-be/src/scripts/herbatica-reviews-seed.tsapps/medusa-be/src/subscriber-helpers/product-review-request-on-payment/helper.tsapps/medusa-be/src/scripts/herbatica-xml-utils.tsapps/medusa-be/src/utils/order-review-requests.tsapps/medusa-be/src/api/store/reviews/helpers.tsapps/medusa-be/src/scripts/herbatica-category-export.tsapps/medusa-be/src/scripts/herbatica-seed.ts
apps/medusa-be/**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (apps/medusa-be/CLAUDE.md)
Run
bunx biome check --write .to lint and auto-format code
Files:
apps/medusa-be/src/modules/product-review/index.tsapps/medusa-be/src/modules/workflow-queue/index.tsapps/medusa-be/src/links/customer-review.tsapps/medusa-be/src/api/store/reviews/middlewares.tsapps/medusa-be/src/links/product-review.tsapps/medusa-be/src/workflows/product-review/steps/create-review.tsapps/medusa-be/src/modules/product-review/migrations/Migration20260610090000.tsapps/medusa-be/src/modules/workflow-queue/migrations/Migration20260610080000.tsapps/medusa-be/src/modules/product-review/models/review-token.tsapps/medusa-be/src/modules/product-review/migrations/Migration20260525120000.tsapps/medusa-be/src/workflows/workflow-queue/steps/delete-workflow-queue-item.tsapps/medusa-be/src/workflows/product-review/types.tsapps/medusa-be/src/modules/product-review/models/review.tsapps/medusa-be/src/workflows/product-review/steps/mark-review-token-used.tsapps/medusa-be/src/api/store/products/[id]/reviews/validators.tsapps/medusa-be/src/modules/workflow-queue/models/workflow-queue-item.tsapps/medusa-be/src/api/admin-app-static.tsapps/medusa-be/src/workflows/send-product-review-request.tsapps/medusa-be/src/modules/workflow-queue/service.tsapps/medusa-be/src/api/store/reviews/validators.tsapps/medusa-be/src/workflows/product-review/workflows/create-review.tsapps/medusa-be/src/scripts/herbatica-seed-config.tsapps/medusa-be/src/api/admin/reviews/status/route.tsapps/medusa-be/src/api/admin/reviews/route.tsapps/medusa-be/medusa-config.tsapps/medusa-be/src/api/admin/reviews/helpers.tsapps/medusa-be/src/modules/product-review/service.tsapps/medusa-be/src/modules/resend/templates.tsapps/medusa-be/src/api/admin/reviews/validators.tsapps/medusa-be/src/api/admin/reviews/middlewares.tsapps/medusa-be/src/api/middlewares.tsapps/medusa-be/src/api/admin/reviews/[id]/route.tsapps/medusa-be/src/api/store/products/[id]/reviews/route.tsapps/medusa-be/src/api/store/reviews/route.tsapps/medusa-be/src/utils/workflow-queue-registry.tsapps/medusa-be/src/jobs/workflow-queue-runner.tsapps/medusa-be/src/subscribers/product-review-request-on-payment.tsapps/medusa-be/src/utils/product-review-request-queue.tsapps/medusa-be/src/admin/routes/reviews/[id]/page.tsxapps/medusa-be/src/admin/lib/reviews.tsapps/medusa-be/src/api/review-normalizers.tsapps/medusa-be/src/modules/resend/service.tsapps/medusa-be/src/admin/routes/reviews/page.tsxapps/medusa-be/src/scripts/herbatica-reviews-seed.tsapps/medusa-be/src/subscriber-helpers/product-review-request-on-payment/helper.tsapps/medusa-be/src/scripts/herbatica-xml-utils.tsapps/medusa-be/src/utils/order-review-requests.tsapps/medusa-be/src/api/store/reviews/helpers.tsapps/medusa-be/src/scripts/herbatica-category-export.tsapps/medusa-be/src/scripts/herbatica-seed.ts
apps/medusa-be/src/**/*.ts
📄 CodeRabbit inference engine (apps/medusa-be/CLAUDE.md)
apps/medusa-be/src/**/*.ts: Useconstand explicit typing withdbService.sqlRaw<Type>()for SQL query results
Resolve logger usingcontainer.resolve<Logger>(ContainerRegistrationKeys.LOGGER)
Resolve Query usingcontainer.resolve<Query>(ContainerRegistrationKeys.QUERY)
UseModules.LOCKING(notModules.LOCK) to resolve locking services
UseModules.CACHING(notModules.CACHE) to resolve caching services
ThrowMedusaErrorwith appropriate type and message for error responses
UseMedusaError.Types.INVALID_DATAfor 400 validation errors
UseMedusaError.Types.NOT_FOUNDfor 404 errors
UseMedusaError.Types.UNAUTHORIZEDfor 401 authentication errors
UseMedusaError.Types.NOT_ALLOWEDfor 400 permission errors
UseMedusaError.Types.DUPLICATE_ERRORfor 422 duplicate entry errors
UseMedusaError.Types.CONFLICTfor 409 conflict errors
Use caching module'scomputeKey()to generate stable cache keys from filters and pagination
Use caching module'sget()with type assertion for cache retrieval
Use caching module'sset()with TTL and tags for cache storage and bulk invalidation
Use caching module'sclear()with tags to bulk-invalidate related cache entries
Always use Redis for caching in multi-container deployments instead of local variables
Batch operations usingCHUNK_SIZEconstant instead of unbounded loops
Files:
apps/medusa-be/src/modules/product-review/index.tsapps/medusa-be/src/modules/workflow-queue/index.tsapps/medusa-be/src/links/customer-review.tsapps/medusa-be/src/api/store/reviews/middlewares.tsapps/medusa-be/src/links/product-review.tsapps/medusa-be/src/workflows/product-review/steps/create-review.tsapps/medusa-be/src/modules/product-review/migrations/Migration20260610090000.tsapps/medusa-be/src/modules/workflow-queue/migrations/Migration20260610080000.tsapps/medusa-be/src/modules/product-review/models/review-token.tsapps/medusa-be/src/modules/product-review/migrations/Migration20260525120000.tsapps/medusa-be/src/workflows/workflow-queue/steps/delete-workflow-queue-item.tsapps/medusa-be/src/workflows/product-review/types.tsapps/medusa-be/src/modules/product-review/models/review.tsapps/medusa-be/src/workflows/product-review/steps/mark-review-token-used.tsapps/medusa-be/src/api/store/products/[id]/reviews/validators.tsapps/medusa-be/src/modules/workflow-queue/models/workflow-queue-item.tsapps/medusa-be/src/api/admin-app-static.tsapps/medusa-be/src/workflows/send-product-review-request.tsapps/medusa-be/src/modules/workflow-queue/service.tsapps/medusa-be/src/api/store/reviews/validators.tsapps/medusa-be/src/workflows/product-review/workflows/create-review.tsapps/medusa-be/src/scripts/herbatica-seed-config.tsapps/medusa-be/src/api/admin/reviews/status/route.tsapps/medusa-be/src/api/admin/reviews/route.tsapps/medusa-be/src/api/admin/reviews/helpers.tsapps/medusa-be/src/modules/product-review/service.tsapps/medusa-be/src/modules/resend/templates.tsapps/medusa-be/src/api/admin/reviews/validators.tsapps/medusa-be/src/api/admin/reviews/middlewares.tsapps/medusa-be/src/api/middlewares.tsapps/medusa-be/src/api/admin/reviews/[id]/route.tsapps/medusa-be/src/api/store/products/[id]/reviews/route.tsapps/medusa-be/src/api/store/reviews/route.tsapps/medusa-be/src/utils/workflow-queue-registry.tsapps/medusa-be/src/jobs/workflow-queue-runner.tsapps/medusa-be/src/subscribers/product-review-request-on-payment.tsapps/medusa-be/src/utils/product-review-request-queue.tsapps/medusa-be/src/admin/lib/reviews.tsapps/medusa-be/src/api/review-normalizers.tsapps/medusa-be/src/modules/resend/service.tsapps/medusa-be/src/scripts/herbatica-reviews-seed.tsapps/medusa-be/src/subscriber-helpers/product-review-request-on-payment/helper.tsapps/medusa-be/src/scripts/herbatica-xml-utils.tsapps/medusa-be/src/utils/order-review-requests.tsapps/medusa-be/src/api/store/reviews/helpers.tsapps/medusa-be/src/scripts/herbatica-category-export.tsapps/medusa-be/src/scripts/herbatica-seed.ts
apps/medusa-be/src/modules/*/index.ts
📄 CodeRabbit inference engine (apps/medusa-be/CLAUDE.md)
Export module key as a constant (e.g.,
MY_MODULE = "my_module") for reuse in imports
Files:
apps/medusa-be/src/modules/product-review/index.tsapps/medusa-be/src/modules/workflow-queue/index.ts
apps/medusa-be/src/modules/**/*.ts
📄 CodeRabbit inference engine (apps/medusa-be/CLAUDE.md)
Modules use isolated containers; Query/Link unavailable during service initialization, defer to
onApplicationStart
Files:
apps/medusa-be/src/modules/product-review/index.tsapps/medusa-be/src/modules/workflow-queue/index.tsapps/medusa-be/src/modules/product-review/migrations/Migration20260610090000.tsapps/medusa-be/src/modules/workflow-queue/migrations/Migration20260610080000.tsapps/medusa-be/src/modules/product-review/models/review-token.tsapps/medusa-be/src/modules/product-review/migrations/Migration20260525120000.tsapps/medusa-be/src/modules/product-review/models/review.tsapps/medusa-be/src/modules/workflow-queue/models/workflow-queue-item.tsapps/medusa-be/src/modules/workflow-queue/service.tsapps/medusa-be/src/modules/product-review/service.tsapps/medusa-be/src/modules/resend/templates.tsapps/medusa-be/src/modules/resend/service.ts
apps/medusa-be/src/modules/**/*.{ts,js}
📄 CodeRabbit inference engine (AGENTS.md)
Medusa backend custom modules should be organized in the apps/medusa-be/src/modules/ directory
Files:
apps/medusa-be/src/modules/product-review/index.tsapps/medusa-be/src/modules/workflow-queue/index.tsapps/medusa-be/src/modules/product-review/migrations/Migration20260610090000.tsapps/medusa-be/src/modules/workflow-queue/migrations/Migration20260610080000.tsapps/medusa-be/src/modules/product-review/models/review-token.tsapps/medusa-be/src/modules/product-review/migrations/Migration20260525120000.tsapps/medusa-be/src/modules/product-review/models/review.tsapps/medusa-be/src/modules/workflow-queue/models/workflow-queue-item.tsapps/medusa-be/src/modules/workflow-queue/service.tsapps/medusa-be/src/modules/product-review/service.tsapps/medusa-be/src/modules/resend/templates.tsapps/medusa-be/src/modules/resend/service.ts
apps/medusa-be/src/api/**/*
📄 CodeRabbit inference engine (CLAUDE.md)
Place custom Medusa backend API endpoints under apps/medusa-be/src/api
Files:
apps/medusa-be/src/api/store/reviews/middlewares.tsapps/medusa-be/src/api/store/products/[id]/reviews/validators.tsapps/medusa-be/src/api/admin-app-static.tsapps/medusa-be/src/api/store/reviews/validators.tsapps/medusa-be/src/api/admin/reviews/status/route.tsapps/medusa-be/src/api/admin/reviews/route.tsapps/medusa-be/src/api/admin/reviews/helpers.tsapps/medusa-be/src/api/admin/reviews/validators.tsapps/medusa-be/src/api/admin/reviews/middlewares.tsapps/medusa-be/src/api/middlewares.tsapps/medusa-be/src/api/admin/reviews/[id]/route.tsapps/medusa-be/src/api/store/products/[id]/reviews/route.tsapps/medusa-be/src/api/store/reviews/route.tsapps/medusa-be/src/api/review-normalizers.tsapps/medusa-be/src/api/store/reviews/helpers.ts
apps/medusa-be/src/api/**/*.ts
📄 CodeRabbit inference engine (apps/medusa-be/CLAUDE.md)
apps/medusa-be/src/api/**/*.ts: Usereq.scope.resolve()to access container in routes
Colocatevalidators.tsandmiddlewares.tswith each route file in the same directory
UsevalidateAndTransformBody(Schema)middleware for POST/PUT request validation
UsevalidateAndTransformQuery(Schema)middleware for GET request query parameter validation
Usereq.validatedBodyin route handlers for type-safe access to validated request body
Files:
apps/medusa-be/src/api/store/reviews/middlewares.tsapps/medusa-be/src/api/store/products/[id]/reviews/validators.tsapps/medusa-be/src/api/admin-app-static.tsapps/medusa-be/src/api/store/reviews/validators.tsapps/medusa-be/src/api/admin/reviews/status/route.tsapps/medusa-be/src/api/admin/reviews/route.tsapps/medusa-be/src/api/admin/reviews/helpers.tsapps/medusa-be/src/api/admin/reviews/validators.tsapps/medusa-be/src/api/admin/reviews/middlewares.tsapps/medusa-be/src/api/middlewares.tsapps/medusa-be/src/api/admin/reviews/[id]/route.tsapps/medusa-be/src/api/store/products/[id]/reviews/route.tsapps/medusa-be/src/api/store/reviews/route.tsapps/medusa-be/src/api/review-normalizers.tsapps/medusa-be/src/api/store/reviews/helpers.ts
apps/medusa-be/src/api/**/*.{ts,js}
📄 CodeRabbit inference engine (AGENTS.md)
Medusa backend API endpoints should be organized in the apps/medusa-be/src/api/ directory
Files:
apps/medusa-be/src/api/store/reviews/middlewares.tsapps/medusa-be/src/api/store/products/[id]/reviews/validators.tsapps/medusa-be/src/api/admin-app-static.tsapps/medusa-be/src/api/store/reviews/validators.tsapps/medusa-be/src/api/admin/reviews/status/route.tsapps/medusa-be/src/api/admin/reviews/route.tsapps/medusa-be/src/api/admin/reviews/helpers.tsapps/medusa-be/src/api/admin/reviews/validators.tsapps/medusa-be/src/api/admin/reviews/middlewares.tsapps/medusa-be/src/api/middlewares.tsapps/medusa-be/src/api/admin/reviews/[id]/route.tsapps/medusa-be/src/api/store/products/[id]/reviews/route.tsapps/medusa-be/src/api/store/reviews/route.tsapps/medusa-be/src/api/review-normalizers.tsapps/medusa-be/src/api/store/reviews/helpers.ts
apps/medusa-be/src/workflows/**/*
📄 CodeRabbit inference engine (CLAUDE.md)
Place business logic workflows under apps/medusa-be/src/workflows
Files:
apps/medusa-be/src/workflows/product-review/steps/create-review.tsapps/medusa-be/src/workflows/workflow-queue/steps/delete-workflow-queue-item.tsapps/medusa-be/src/workflows/product-review/types.tsapps/medusa-be/src/workflows/product-review/steps/mark-review-token-used.tsapps/medusa-be/src/workflows/send-product-review-request.tsapps/medusa-be/src/workflows/product-review/workflows/create-review.ts
apps/medusa-be/src/workflows/**/*.ts
📄 CodeRabbit inference engine (apps/medusa-be/CLAUDE.md)
apps/medusa-be/src/workflows/**/*.ts: Use the second parameter{ container }object to access container in workflow steps
UsecreateStep()to define workflow steps with input validation and response wrapping
UsecreateWorkflow()to define multi-step business logic with rollback support
Returnnew StepResponse()from workflow steps to pass data to next steps
Returnnew WorkflowResponse()from workflows to pass final result to caller
Usetransform()in workflows for data manipulation only; cannot contain side effects
Usewhen().then()for conditional logic in workflows instead of if statements
Do not reassign or iterate workflow variables; variable definitions are static at definition time
UseuseQueryGraphStep()for Query operations within workflows
UseacquireLockStep(),releaseLockStep()for workflow-level locking instead of manual job locking
Files:
apps/medusa-be/src/workflows/product-review/steps/create-review.tsapps/medusa-be/src/workflows/workflow-queue/steps/delete-workflow-queue-item.tsapps/medusa-be/src/workflows/product-review/types.tsapps/medusa-be/src/workflows/product-review/steps/mark-review-token-used.tsapps/medusa-be/src/workflows/send-product-review-request.tsapps/medusa-be/src/workflows/product-review/workflows/create-review.ts
apps/medusa-be/src/workflows/**/*.{ts,js}
📄 CodeRabbit inference engine (AGENTS.md)
Medusa backend business logic should be implemented as workflows in the apps/medusa-be/src/workflows/ directory
Files:
apps/medusa-be/src/workflows/product-review/steps/create-review.tsapps/medusa-be/src/workflows/workflow-queue/steps/delete-workflow-queue-item.tsapps/medusa-be/src/workflows/product-review/types.tsapps/medusa-be/src/workflows/product-review/steps/mark-review-token-used.tsapps/medusa-be/src/workflows/send-product-review-request.tsapps/medusa-be/src/workflows/product-review/workflows/create-review.ts
apps/medusa-be/src/modules/**/models/*.ts
📄 CodeRabbit inference engine (apps/medusa-be/CLAUDE.md)
apps/medusa-be/src/modules/**/models/*.ts: Use soft-delete safe indexes for unique constraints in data models; includewhere: { deleted_at: null }in DML format
Usemodel.float()for lower-precision numbers; usemodel.bigNumber()for high-precision values like money
Use provider identifier format{identifier}_{id}in DBprovider_idfield (e.g.,my_shipping_default)
Files:
apps/medusa-be/src/modules/product-review/models/review-token.tsapps/medusa-be/src/modules/product-review/models/review.tsapps/medusa-be/src/modules/workflow-queue/models/workflow-queue-item.ts
apps/medusa-be/src/api/**/validators.ts
📄 CodeRabbit inference engine (apps/medusa-be/CLAUDE.md)
Define Zod schemas and type inference in
validators.tsalongside route definitions
Files:
apps/medusa-be/src/api/store/products/[id]/reviews/validators.tsapps/medusa-be/src/api/store/reviews/validators.tsapps/medusa-be/src/api/admin/reviews/validators.ts
**/package.json
📄 CodeRabbit inference engine (CLAUDE.md)
Use pnpm CLI to add dependencies; never edit package.json directly
Files:
apps/medusa-be/package.json
apps/medusa-be/src/modules/*/service.ts
📄 CodeRabbit inference engine (apps/medusa-be/CLAUDE.md)
apps/medusa-be/src/modules/*/service.ts: ExtendMedusaServicein module services for automatic CRUD methods
Callsuper(container, options)in module service constructors; do not usesuper(...arguments)
Implement rate limiting and token management in service layer, not in HTTP client
Use workflows for cross-module orchestration; do not use Query/Link in module service constructors
Use Query and Link patterns to access other modules from services instead of direct imports
Files:
apps/medusa-be/src/modules/workflow-queue/service.tsapps/medusa-be/src/modules/product-review/service.tsapps/medusa-be/src/modules/resend/service.ts
apps/medusa-be/src/scripts/**/*.ts
📄 CodeRabbit inference engine (apps/medusa-be/CLAUDE.md)
apps/medusa-be/src/scripts/**/*.ts: Usemedusa exec ./path/to/script.ts [args]to run one-off scripts instead of creating HTTP endpoints
Use script patternnpx medusa exec ./src/scripts/startup.tsin startup hooks
Use destructive operations inmedusa execscripts, never in unprotected GET endpoints
Files:
apps/medusa-be/src/scripts/herbatica-seed-config.tsapps/medusa-be/src/scripts/herbatica-reviews-seed.tsapps/medusa-be/src/scripts/herbatica-xml-utils.tsapps/medusa-be/src/scripts/herbatica-category-export.tsapps/medusa-be/src/scripts/herbatica-seed.ts
apps/medusa-be/src/api/admin/**/*.ts
📄 CodeRabbit inference engine (apps/medusa-be/CLAUDE.md)
apps/medusa-be/src/api/admin/**/*.ts: Do not name variablesconfigin admin routes as it shadowsexport const config = defineRouteConfig()
Admin routes are automatically protected and do not require explicit auth middleware
Files:
apps/medusa-be/src/api/admin/reviews/status/route.tsapps/medusa-be/src/api/admin/reviews/route.tsapps/medusa-be/src/api/admin/reviews/helpers.tsapps/medusa-be/src/api/admin/reviews/validators.tsapps/medusa-be/src/api/admin/reviews/middlewares.tsapps/medusa-be/src/api/admin/reviews/[id]/route.ts
apps/medusa-be/**/medusa-config.ts
📄 CodeRabbit inference engine (apps/medusa-be/CLAUDE.md)
Use feature flag env vars in
medusa-config.tsevaluated at BUILD time, not runtime
Files:
apps/medusa-be/medusa-config.ts
apps/medusa-be/src/jobs/**/*
📄 CodeRabbit inference engine (CLAUDE.md)
Place background jobs under apps/medusa-be/src/jobs
Files:
apps/medusa-be/src/jobs/workflow-queue-runner.ts
apps/medusa-be/src/jobs/**/*.ts
📄 CodeRabbit inference engine (apps/medusa-be/CLAUDE.md)
apps/medusa-be/src/jobs/**/*.ts: Usecontainer.resolve()to access services in jobs and loaders
Lock overlapping background jobs to prevent concurrent conflicts
Use locking module'sexecute()method with timeout and TTL for job synchronization
Handle locking timeout errors by checking if error message includes 'Timed-out'
Do not place test files insrc/jobs/__tests__/as Medusa loads allsrc/jobs/files at runtime
Files:
apps/medusa-be/src/jobs/workflow-queue-runner.ts
apps/medusa-be/src/jobs/**/*.{ts,js}
📄 CodeRabbit inference engine (AGENTS.md)
Medusa backend background jobs should be organized in the apps/medusa-be/src/jobs/ directory
Files:
apps/medusa-be/src/jobs/workflow-queue-runner.ts
apps/medusa-be/src/subscribers/**/*
📄 CodeRabbit inference engine (CLAUDE.md)
Place event subscribers under apps/medusa-be/src/subscribers
Files:
apps/medusa-be/src/subscribers/product-review-request-on-payment.ts
apps/medusa-be/src/subscribers/**/*.{ts,js}
📄 CodeRabbit inference engine (AGENTS.md)
Medusa backend event subscribers should be organized in the apps/medusa-be/src/subscribers/ directory
Files:
apps/medusa-be/src/subscribers/product-review-request-on-payment.ts
apps/medusa-be/src/admin/**/*
📄 CodeRabbit inference engine (CLAUDE.md)
Place admin panel customizations under apps/medusa-be/src/admin
Files:
apps/medusa-be/src/admin/routes/reviews/[id]/page.tsxapps/medusa-be/src/admin/lib/reviews.tsapps/medusa-be/src/admin/routes/reviews/page.tsx
apps/medusa-be/src/admin/**/*.{ts,tsx}
📄 CodeRabbit inference engine (apps/medusa-be/CLAUDE.md)
apps/medusa-be/src/admin/**/*.{ts,tsx}: Useimport.meta.env.VITE_*for public env vars in React admin app; no secret env vars
Useimport.meta.env.DEVandimport.meta.env.PRODfor environment detection in admin app
Files:
apps/medusa-be/src/admin/routes/reviews/[id]/page.tsxapps/medusa-be/src/admin/lib/reviews.tsapps/medusa-be/src/admin/routes/reviews/page.tsx
apps/medusa-be/src/admin/**/*.{ts,js}
📄 CodeRabbit inference engine (AGENTS.md)
Medusa backend admin panel customizations should be organized in the apps/medusa-be/src/admin/ directory
Files:
apps/medusa-be/src/admin/lib/reviews.ts
🧠 Learnings (7)
📚 Learning: 2026-05-18T16:32:35.366Z
Learnt from: redeyecz
Repo: TechsioCZ/new-engine PR: 409
File: apps/medusa-be/src/modules/producer/migrations/Migration20260518122326.ts:9-35
Timestamp: 2026-05-18T16:32:35.366Z
Learning: In `apps/medusa-be` MikroORM migration files under `src/modules/**/migrations/`, keep SQL schema-agnostic: do not explicitly qualify tables/indexes with a schema prefix (e.g., avoid `
Applied to files:
apps/medusa-be/src/modules/product-review/migrations/Migration20260610090000.tsapps/medusa-be/src/modules/workflow-queue/migrations/Migration20260610080000.tsapps/medusa-be/src/modules/product-review/migrations/Migration20260525120000.ts
📚 Learning: 2026-02-05T14:43:17.404Z
Learnt from: KaiUweCZE
Repo: NMIT-WR/new-engine PR: 324
File: apps/medusa-be/package.json:0-0
Timestamp: 2026-02-05T14:43:17.404Z
Learning: Validate and enforce React 19 compatibility across monorepo workspaces. Since Medusa UI supports React 19 via root package.json overrides and Medusa Cloud prerequisites show React 19 overrides for npm workspaces, ensure workspace root and all relevant package.json files align with React 19 (18+ requirement is satisfied). When reviewing, verify that overrides exist in the root package.json and that dependent packages in apps or packages directories declare React 19 (or compatible) in their peerDependencies or dependencies as appropriate for workspace usage.
Applied to files:
apps/medusa-be/package.json
📚 Learning: 2026-05-07T19:05:58.339Z
Learnt from: redeyecz
Repo: TechsioCZ/new-engine PR: 390
File: apps/medusa-be/package.json:78-81
Timestamp: 2026-05-07T19:05:58.339Z
Learning: When reviewing changes to `package.json`, do not automatically flag dependency additions/removals as "manually edited" or as "bypassing the pnpm lockfile" just because the `package.json` diff shows only that file changed. First verify whether `pnpm-lock.yaml` is missing the corresponding entries. Since `pnpm add` updates both `package.json` and `pnpm-lock.yaml` together, legitimate changes can appear in the `package.json` diff while still being properly tracked in the lockfile.
Applied to files:
apps/medusa-be/package.json
📚 Learning: 2026-05-20T15:58:53.048Z
Learnt from: redeyecz
Repo: TechsioCZ/new-engine PR: 413
File: apps/medusa-be/package.json:77-80
Timestamp: 2026-05-20T15:58:53.048Z
Learning: When reviewing monorepo `package.json` files, treat any dependencies/devDependencies using the `paykit-sdk/*` scope (e.g., `paykit-sdk/core`, `paykit-sdk/stripe`, `paykit-sdk/comgate`, `paykit-sdk/gopay`) as coming from the TechsioCZ/new-engine private npm registry. Do not flag dependency version constraints (e.g., `^1.2.0`) as invalid merely because those packages/versions are not found on the public npm registry. Public-web/private-web availability checks against the public npm API are not applicable for these packages; if validation is needed, rely on the private registry/CI install behavior instead.
Applied to files:
apps/medusa-be/package.json
📚 Learning: 2026-02-25T14:46:02.729Z
Learnt from: redeyecz
Repo: TechsioCZ/new-engine PR: 335
File: apps/zane-operator/src/db.ts:205-207
Timestamp: 2026-02-25T14:46:02.729Z
Learning: Enforce PostgreSQL 18+ as the minimum version across docker-compose files. Since the repo uses postgres:18.1-alpine (evidence in docker-compose.yaml), ensure all docker-compose service images for PostgreSQL use 18.1-alpine or newer. When reviewing, look for postgres images with a tag below 18 (e.g., postgres:<older-version>) and update to 18.1-alpine or a newer compatible tag. This guideline applies to all docker-compose YAML files that define PostgreSQL services.
Applied to files:
docker-compose.yaml
📚 Learning: 2025-12-16T19:45:17.746Z
Learnt from: BleedingDev
Repo: NMIT-WR/new-engine PR: 207
File: libs/ui/src/molecules/select.tsx:50-50
Timestamp: 2025-12-16T19:45:17.746Z
Learning: When reviewing Tailwind classes in TSX/TS files, prefer using square brackets for arbitrary CSS values and complex expressions. Specifically: - Do not use the parentheses syntax (z-(--z-index)) for anything beyond simple CSS variable references; this syntax auto-wraps in var() and cannot handle calc or complex functions. - Use the square brackets syntax (e.g., h-[calc(var(--available-height)-var(--spacing-content))]) for calc expressions, var with calc, and any complex CSS expressions. This rule applies broadly to Tailwind v4 usage in TSX code across the project.
Applied to files:
apps/medusa-be/src/admin/routes/reviews/[id]/page.tsxapps/medusa-be/src/admin/routes/reviews/page.tsx
📚 Learning: 2026-05-07T12:06:55.558Z
Learnt from: redeyecz
Repo: TechsioCZ/new-engine PR: 375
File: apps/medusa-be/src/admin/widgets/order-payment-reminder.tsx:3-11
Timestamp: 2026-05-07T12:06:55.558Z
Learning: In Medusa admin code under `apps/medusa-be/src/admin/` (admin widgets/routes), UI components must be imported from `medusajs/ui` (the Medusa admin UI kit). Do not apply the project-wide `libs/ui/atoms/*` and `libs/ui/molecules/*` import conventions to these files, and never flag `medusajs/ui` imports in this admin directory as violating the `libs/ui` convention.
Applied to files:
apps/medusa-be/src/admin/routes/reviews/[id]/page.tsxapps/medusa-be/src/admin/routes/reviews/page.tsx
🪛 ast-grep (0.43.0)
apps/medusa-be/src/workflows/send-product-review-request.ts
[warning] 71-74: Manual HTML sanitization detected using string replacement methods. Manual sanitization is error-prone and can be bypassed. Use dedicated HTML sanitization libraries like 'sanitize-html' or 'DOMPurify' instead.
Context: value
.replaceAll("&", "&")
.replaceAll("<", "<")
.replaceAll(">", ">")
Note: [CWE-79] Improper Neutralization of Input During Web Page Generation
(manual-html-sanitization)
[warning] 71-73: Manual HTML sanitization detected using string replacement methods. Manual sanitization is error-prone and can be bypassed. Use dedicated HTML sanitization libraries like 'sanitize-html' or 'DOMPurify' instead.
Context: value
.replaceAll("&", "&")
.replaceAll("<", "<")
Note: [CWE-79] Improper Neutralization of Input During Web Page Generation
(manual-html-sanitization)
apps/medusa-be/src/scripts/herbatica-xml-utils.ts
[warning] 72-72: Regular expression constructed from variable input detected. This can lead to Regular Expression Denial of Service (ReDoS) attacks if the variable contains malicious patterns. Use libraries like 'recheck' to validate regex safety or use static patterns.
Context: new RegExp(<${tag}(\\s[^>]*)?>([\\s\\S]*?)<\\/${tag}>, "g")
Note: [CWE-1333] Inefficient Regular Expression Complexity
(regexp-from-variable)
[warning] 89-89: Regular expression constructed from variable input detected. This can lead to Regular Expression Denial of Service (ReDoS) attacks if the variable contains malicious patterns. Use libraries like 'recheck' to validate regex safety or use static patterns.
Context: new RegExp(<${tag}(?:\\s[^>]*)?>([\\s\\S]*?)<\\/${tag}>)
Note: [CWE-1333] Inefficient Regular Expression Complexity
(regexp-from-variable)
🪛 dotenv-linter (4.0.0)
.env.docker
[warning] 79-79: [UnorderedKey] The DC_HERBATICA_REVIEWS_XML_PATH key should go before the DC_HERBATICA_XML_PATH key
(UnorderedKey)
|
Incremental review completed after Posting summary findings here instead of inline comments because the review environment blocked the new inline comment submission. WARNING: WARNING: SUGGESTION: |
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
apps/medusa-be/src/modules/product-review/migrations/Migration20260610090000.ts (1)
8-10: 🧹 Nitpick | 🔵 Trivial | ⚡ Quick winReconsider the partial index on
deleted_at.The index
IDX_review_token_deleted_aton columndeleted_atwith conditionWHERE deleted_at IS NULLwill only contain rows wheredeleted_atisNULL, making every indexed valueNULL. This provides no selectivity benefit for queries.For soft-delete patterns, you typically either:
- Rely on the
WHERE deleted_at IS NULLcondition in queries without a dedicated index on that column- Add the
WHERE deleted_at IS NULLcondition to indexes on other columns (which you've already done correctly in lines 12, 15, 18, 21, 24)Unless there's a specific query pattern that requires indexing
deleted_atitself, this index can be removed.♻️ Proposed fix to remove unnecessary index
`create table if not exists "review_token" ("id" text not null, "token" text not null, "order_id" text not null, "product_id" text not null, "customer_id" text null, "email" text not null, "used_at" timestamptz null, "expires_at" timestamptz null, "created_at" timestamptz not null default now(), "updated_at" timestamptz not null default now(), "deleted_at" timestamptz null, constraint "review_token_pkey" primary key ("id"));` ) - this.addSql( - `CREATE INDEX IF NOT EXISTS "IDX_review_token_deleted_at" ON "review_token" (deleted_at) WHERE deleted_at IS NULL;` - ) this.addSql(🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/medusa-be/src/modules/product-review/migrations/Migration20260610090000.ts` around lines 8 - 10, Remove the unnecessary partial index creation for deleted_at in Migration20260610090000: delete the addSql call that creates "IDX_review_token_deleted_at" (`CREATE INDEX IF NOT EXISTS "IDX_review_token_deleted_at" ON "review_token" (deleted_at) WHERE deleted_at IS NULL;`) since it only indexes NULL values and provides no selectivity; leave the other partial indexes (the ones already adding WHERE deleted_at IS NULL to other columns) intact.apps/medusa-be/src/api/store/reviews/helpers.ts (1)
70-79:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winUse standard English "Anonymous" instead of "Anonym".
Line 77 uses
"Anonym"for the first name of review token authors. This is not standard English and may confuse users. The conventional term is"Anonymous".🛡️ Proposed fix
export const getReviewAuthorName = ({ customer, reviewToken, }: { customer?: CustomerRecord reviewToken?: ReviewTokenDTO }) => ({ - first_name: reviewToken ? "Anonym" : customer?.first_name ?? null, + first_name: reviewToken ? "Anonymous" : customer?.first_name ?? null, last_name: reviewToken ? null : customer?.last_name ?? null, })🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/medusa-be/src/api/store/reviews/helpers.ts` around lines 70 - 79, The getReviewAuthorName helper returns the placeholder name "Anonym" for reviewToken authors; update it to use the standard English term "Anonymous". Locate the getReviewAuthorName function and replace the literal "Anonym" with "Anonymous", and run/adjust any tests or UI code that asserts the exact placeholder string to reflect the new value.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@apps/medusa-be/src/modules/workflow-queue/service.ts`:
- Line 32: The line creating manager uses an unchecked cast "(this as unknown as
ServiceWithBaseRepository).baseRepository_.getFreshManager(sharedContext)" which
relies on private Medusa internals and skips runtime validation; replace it by
validating that this implements the expected interface (e.g., check for a public
method/property like getManager or baseRepository) before accessing repository
functionality, and use the public API to obtain a fresh manager (inject or call
the service's public repository/manager accessor rather than
baseRepository_.getFreshManager). Specifically, remove the unchecked "as" cast,
add a runtime guard that ensures this has the required member, and call the
public manager/repository accessor on the service (referencing the manager
variable, baseRepository_.getFreshManager, and ServiceWithBaseRepository to
locate the code) so you avoid touching private fields.
---
Outside diff comments:
In `@apps/medusa-be/src/api/store/reviews/helpers.ts`:
- Around line 70-79: The getReviewAuthorName helper returns the placeholder name
"Anonym" for reviewToken authors; update it to use the standard English term
"Anonymous". Locate the getReviewAuthorName function and replace the literal
"Anonym" with "Anonymous", and run/adjust any tests or UI code that asserts the
exact placeholder string to reflect the new value.
In
`@apps/medusa-be/src/modules/product-review/migrations/Migration20260610090000.ts`:
- Around line 8-10: Remove the unnecessary partial index creation for deleted_at
in Migration20260610090000: delete the addSql call that creates
"IDX_review_token_deleted_at" (`CREATE INDEX IF NOT EXISTS
"IDX_review_token_deleted_at" ON "review_token" (deleted_at) WHERE deleted_at IS
NULL;`) since it only indexes NULL values and provides no selectivity; leave the
other partial indexes (the ones already adding WHERE deleted_at IS NULL to other
columns) intact.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: f93f4258-7ad0-49da-ab15-23b4f25616bb
📒 Files selected for processing (31)
.env.dockerapps/medusa-be/src/admin/lib/reviews.tsapps/medusa-be/src/admin/routes/reviews/[id]/page.tsxapps/medusa-be/src/api/admin-app-static.tsapps/medusa-be/src/api/admin/reviews/[id]/route.tsapps/medusa-be/src/api/admin/reviews/helpers.tsapps/medusa-be/src/api/admin/reviews/route.tsapps/medusa-be/src/api/admin/reviews/status/route.tsapps/medusa-be/src/api/review-normalizers.tsapps/medusa-be/src/api/store/products/[id]/reviews/route.tsapps/medusa-be/src/api/store/reviews/helpers.tsapps/medusa-be/src/jobs/workflow-queue-runner.tsapps/medusa-be/src/modules/product-review/migrations/Migration20260610090000.tsapps/medusa-be/src/modules/product-review/service.tsapps/medusa-be/src/modules/resend/service.tsapps/medusa-be/src/modules/workflow-queue/index.tsapps/medusa-be/src/modules/workflow-queue/migrations/Migration20260610080000.tsapps/medusa-be/src/modules/workflow-queue/service.tsapps/medusa-be/src/scripts/herbatica-reviews-seed.tsapps/medusa-be/src/scripts/herbatica-xml-utils.tsapps/medusa-be/src/subscriber-helpers/product-review-request-on-payment/helper.tsapps/medusa-be/src/utils/order-review-requests.tsapps/medusa-be/src/utils/product-review-request-queue.tsapps/medusa-be/src/utils/workflow-queue-registry.tsapps/medusa-be/src/workflows/product-review/steps/update-review-status.tsapps/medusa-be/src/workflows/product-review/steps/update-review.tsapps/medusa-be/src/workflows/product-review/types.tsapps/medusa-be/src/workflows/product-review/workflows/update-review-status.tsapps/medusa-be/src/workflows/product-review/workflows/update-review.tsapps/medusa-be/src/workflows/send-product-review-request.tsdocker-compose.yaml
📜 Review details
⏰ 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: Greptile Review
- GitHub Check: main
- GitHub Check: Kilo Code Review
🧰 Additional context used
📓 Path-based instructions (22)
apps/medusa-be/src/workflows/**/*
📄 CodeRabbit inference engine (CLAUDE.md)
Place business logic workflows under apps/medusa-be/src/workflows
Files:
apps/medusa-be/src/workflows/product-review/workflows/update-review-status.tsapps/medusa-be/src/workflows/product-review/steps/update-review.tsapps/medusa-be/src/workflows/product-review/steps/update-review-status.tsapps/medusa-be/src/workflows/product-review/workflows/update-review.tsapps/medusa-be/src/workflows/product-review/types.tsapps/medusa-be/src/workflows/send-product-review-request.ts
apps/medusa-be/**/*.{ts,tsx}
📄 CodeRabbit inference engine (apps/medusa-be/CLAUDE.md)
apps/medusa-be/**/*.{ts,tsx}: Runnpx tsc --noEmitfor typechecking before committing
Always use braces around conditional blocks, even for single statements; Biome will expand them
Declare one variable perconst/letstatement, not multiple on one line
Use nullish coalescing operator (??) instead of logical OR (||) for default values
Do not use non-null assertions (!); use type guards or validation instead
Annotate type asunknownwhen accessing dynamic object properties before applying type guards
Use comments only to explain 'why', never 'what'; self-document code with clear naming
Extract pure functions to separate files for testability without runtime dependencies
UseModules.*andContainerRegistrationKeys.*constants instead of hardcoding module/key strings
Do not use non-null assertions in TypeScript code; validate or use type guards instead
Validate data before type casting; never useas Typewithout prior validation
Files:
apps/medusa-be/src/workflows/product-review/workflows/update-review-status.tsapps/medusa-be/src/workflows/product-review/steps/update-review.tsapps/medusa-be/src/workflows/product-review/steps/update-review-status.tsapps/medusa-be/src/modules/workflow-queue/index.tsapps/medusa-be/src/api/admin/reviews/helpers.tsapps/medusa-be/src/modules/workflow-queue/migrations/Migration20260610080000.tsapps/medusa-be/src/workflows/product-review/workflows/update-review.tsapps/medusa-be/src/workflows/product-review/types.tsapps/medusa-be/src/utils/workflow-queue-registry.tsapps/medusa-be/src/modules/product-review/service.tsapps/medusa-be/src/api/admin/reviews/status/route.tsapps/medusa-be/src/api/admin-app-static.tsapps/medusa-be/src/admin/routes/reviews/[id]/page.tsxapps/medusa-be/src/modules/product-review/migrations/Migration20260610090000.tsapps/medusa-be/src/api/admin/reviews/[id]/route.tsapps/medusa-be/src/api/admin/reviews/route.tsapps/medusa-be/src/workflows/send-product-review-request.tsapps/medusa-be/src/modules/workflow-queue/service.tsapps/medusa-be/src/utils/product-review-request-queue.tsapps/medusa-be/src/admin/lib/reviews.tsapps/medusa-be/src/utils/order-review-requests.tsapps/medusa-be/src/api/store/products/[id]/reviews/route.tsapps/medusa-be/src/modules/resend/service.tsapps/medusa-be/src/api/store/reviews/helpers.tsapps/medusa-be/src/api/review-normalizers.tsapps/medusa-be/src/scripts/herbatica-xml-utils.tsapps/medusa-be/src/jobs/workflow-queue-runner.tsapps/medusa-be/src/subscriber-helpers/product-review-request-on-payment/helper.tsapps/medusa-be/src/scripts/herbatica-reviews-seed.ts
apps/medusa-be/**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (apps/medusa-be/CLAUDE.md)
Run
bunx biome check --write .to lint and auto-format code
Files:
apps/medusa-be/src/workflows/product-review/workflows/update-review-status.tsapps/medusa-be/src/workflows/product-review/steps/update-review.tsapps/medusa-be/src/workflows/product-review/steps/update-review-status.tsapps/medusa-be/src/modules/workflow-queue/index.tsapps/medusa-be/src/api/admin/reviews/helpers.tsapps/medusa-be/src/modules/workflow-queue/migrations/Migration20260610080000.tsapps/medusa-be/src/workflows/product-review/workflows/update-review.tsapps/medusa-be/src/workflows/product-review/types.tsapps/medusa-be/src/utils/workflow-queue-registry.tsapps/medusa-be/src/modules/product-review/service.tsapps/medusa-be/src/api/admin/reviews/status/route.tsapps/medusa-be/src/api/admin-app-static.tsapps/medusa-be/src/admin/routes/reviews/[id]/page.tsxapps/medusa-be/src/modules/product-review/migrations/Migration20260610090000.tsapps/medusa-be/src/api/admin/reviews/[id]/route.tsapps/medusa-be/src/api/admin/reviews/route.tsapps/medusa-be/src/workflows/send-product-review-request.tsapps/medusa-be/src/modules/workflow-queue/service.tsapps/medusa-be/src/utils/product-review-request-queue.tsapps/medusa-be/src/admin/lib/reviews.tsapps/medusa-be/src/utils/order-review-requests.tsapps/medusa-be/src/api/store/products/[id]/reviews/route.tsapps/medusa-be/src/modules/resend/service.tsapps/medusa-be/src/api/store/reviews/helpers.tsapps/medusa-be/src/api/review-normalizers.tsapps/medusa-be/src/scripts/herbatica-xml-utils.tsapps/medusa-be/src/jobs/workflow-queue-runner.tsapps/medusa-be/src/subscriber-helpers/product-review-request-on-payment/helper.tsapps/medusa-be/src/scripts/herbatica-reviews-seed.ts
apps/medusa-be/src/**/*.ts
📄 CodeRabbit inference engine (apps/medusa-be/CLAUDE.md)
apps/medusa-be/src/**/*.ts: Useconstand explicit typing withdbService.sqlRaw<Type>()for SQL query results
Resolve logger usingcontainer.resolve<Logger>(ContainerRegistrationKeys.LOGGER)
Resolve Query usingcontainer.resolve<Query>(ContainerRegistrationKeys.QUERY)
UseModules.LOCKING(notModules.LOCK) to resolve locking services
UseModules.CACHING(notModules.CACHE) to resolve caching services
ThrowMedusaErrorwith appropriate type and message for error responses
UseMedusaError.Types.INVALID_DATAfor 400 validation errors
UseMedusaError.Types.NOT_FOUNDfor 404 errors
UseMedusaError.Types.UNAUTHORIZEDfor 401 authentication errors
UseMedusaError.Types.NOT_ALLOWEDfor 400 permission errors
UseMedusaError.Types.DUPLICATE_ERRORfor 422 duplicate entry errors
UseMedusaError.Types.CONFLICTfor 409 conflict errors
Use caching module'scomputeKey()to generate stable cache keys from filters and pagination
Use caching module'sget()with type assertion for cache retrieval
Use caching module'sset()with TTL and tags for cache storage and bulk invalidation
Use caching module'sclear()with tags to bulk-invalidate related cache entries
Always use Redis for caching in multi-container deployments instead of local variables
Batch operations usingCHUNK_SIZEconstant instead of unbounded loops
Files:
apps/medusa-be/src/workflows/product-review/workflows/update-review-status.tsapps/medusa-be/src/workflows/product-review/steps/update-review.tsapps/medusa-be/src/workflows/product-review/steps/update-review-status.tsapps/medusa-be/src/modules/workflow-queue/index.tsapps/medusa-be/src/api/admin/reviews/helpers.tsapps/medusa-be/src/modules/workflow-queue/migrations/Migration20260610080000.tsapps/medusa-be/src/workflows/product-review/workflows/update-review.tsapps/medusa-be/src/workflows/product-review/types.tsapps/medusa-be/src/utils/workflow-queue-registry.tsapps/medusa-be/src/modules/product-review/service.tsapps/medusa-be/src/api/admin/reviews/status/route.tsapps/medusa-be/src/api/admin-app-static.tsapps/medusa-be/src/modules/product-review/migrations/Migration20260610090000.tsapps/medusa-be/src/api/admin/reviews/[id]/route.tsapps/medusa-be/src/api/admin/reviews/route.tsapps/medusa-be/src/workflows/send-product-review-request.tsapps/medusa-be/src/modules/workflow-queue/service.tsapps/medusa-be/src/utils/product-review-request-queue.tsapps/medusa-be/src/admin/lib/reviews.tsapps/medusa-be/src/utils/order-review-requests.tsapps/medusa-be/src/api/store/products/[id]/reviews/route.tsapps/medusa-be/src/modules/resend/service.tsapps/medusa-be/src/api/store/reviews/helpers.tsapps/medusa-be/src/api/review-normalizers.tsapps/medusa-be/src/scripts/herbatica-xml-utils.tsapps/medusa-be/src/jobs/workflow-queue-runner.tsapps/medusa-be/src/subscriber-helpers/product-review-request-on-payment/helper.tsapps/medusa-be/src/scripts/herbatica-reviews-seed.ts
apps/medusa-be/src/workflows/**/*.ts
📄 CodeRabbit inference engine (apps/medusa-be/CLAUDE.md)
apps/medusa-be/src/workflows/**/*.ts: Use the second parameter{ container }object to access container in workflow steps
UsecreateStep()to define workflow steps with input validation and response wrapping
UsecreateWorkflow()to define multi-step business logic with rollback support
Returnnew StepResponse()from workflow steps to pass data to next steps
Returnnew WorkflowResponse()from workflows to pass final result to caller
Usetransform()in workflows for data manipulation only; cannot contain side effects
Usewhen().then()for conditional logic in workflows instead of if statements
Do not reassign or iterate workflow variables; variable definitions are static at definition time
UseuseQueryGraphStep()for Query operations within workflows
UseacquireLockStep(),releaseLockStep()for workflow-level locking instead of manual job locking
Files:
apps/medusa-be/src/workflows/product-review/workflows/update-review-status.tsapps/medusa-be/src/workflows/product-review/steps/update-review.tsapps/medusa-be/src/workflows/product-review/steps/update-review-status.tsapps/medusa-be/src/workflows/product-review/workflows/update-review.tsapps/medusa-be/src/workflows/product-review/types.tsapps/medusa-be/src/workflows/send-product-review-request.ts
apps/medusa-be/src/workflows/**/*.{ts,js}
📄 CodeRabbit inference engine (AGENTS.md)
Medusa backend business logic should be implemented as workflows in the apps/medusa-be/src/workflows/ directory
Files:
apps/medusa-be/src/workflows/product-review/workflows/update-review-status.tsapps/medusa-be/src/workflows/product-review/steps/update-review.tsapps/medusa-be/src/workflows/product-review/steps/update-review-status.tsapps/medusa-be/src/workflows/product-review/workflows/update-review.tsapps/medusa-be/src/workflows/product-review/types.tsapps/medusa-be/src/workflows/send-product-review-request.ts
apps/medusa-be/src/modules/**/*
📄 CodeRabbit inference engine (CLAUDE.md)
Place custom Medusa modules under apps/medusa-be/src/modules
Module directories use hyphens (
my-module/), but module keys in config use underscores (my_module)
Files:
apps/medusa-be/src/modules/workflow-queue/index.tsapps/medusa-be/src/modules/workflow-queue/migrations/Migration20260610080000.tsapps/medusa-be/src/modules/product-review/service.tsapps/medusa-be/src/modules/product-review/migrations/Migration20260610090000.tsapps/medusa-be/src/modules/workflow-queue/service.tsapps/medusa-be/src/modules/resend/service.ts
apps/medusa-be/src/modules/*/index.ts
📄 CodeRabbit inference engine (apps/medusa-be/CLAUDE.md)
Export module key as a constant (e.g.,
MY_MODULE = "my_module") for reuse in imports
Files:
apps/medusa-be/src/modules/workflow-queue/index.ts
apps/medusa-be/src/modules/**/*.ts
📄 CodeRabbit inference engine (apps/medusa-be/CLAUDE.md)
Modules use isolated containers; Query/Link unavailable during service initialization, defer to
onApplicationStart
Files:
apps/medusa-be/src/modules/workflow-queue/index.tsapps/medusa-be/src/modules/workflow-queue/migrations/Migration20260610080000.tsapps/medusa-be/src/modules/product-review/service.tsapps/medusa-be/src/modules/product-review/migrations/Migration20260610090000.tsapps/medusa-be/src/modules/workflow-queue/service.tsapps/medusa-be/src/modules/resend/service.ts
apps/medusa-be/src/modules/**/*.{ts,js}
📄 CodeRabbit inference engine (AGENTS.md)
Medusa backend custom modules should be organized in the apps/medusa-be/src/modules/ directory
Files:
apps/medusa-be/src/modules/workflow-queue/index.tsapps/medusa-be/src/modules/workflow-queue/migrations/Migration20260610080000.tsapps/medusa-be/src/modules/product-review/service.tsapps/medusa-be/src/modules/product-review/migrations/Migration20260610090000.tsapps/medusa-be/src/modules/workflow-queue/service.tsapps/medusa-be/src/modules/resend/service.ts
apps/medusa-be/src/api/**/*
📄 CodeRabbit inference engine (CLAUDE.md)
Place custom Medusa backend API endpoints under apps/medusa-be/src/api
Files:
apps/medusa-be/src/api/admin/reviews/helpers.tsapps/medusa-be/src/api/admin/reviews/status/route.tsapps/medusa-be/src/api/admin-app-static.tsapps/medusa-be/src/api/admin/reviews/[id]/route.tsapps/medusa-be/src/api/admin/reviews/route.tsapps/medusa-be/src/api/store/products/[id]/reviews/route.tsapps/medusa-be/src/api/store/reviews/helpers.tsapps/medusa-be/src/api/review-normalizers.ts
apps/medusa-be/src/api/admin/**/*.ts
📄 CodeRabbit inference engine (apps/medusa-be/CLAUDE.md)
apps/medusa-be/src/api/admin/**/*.ts: Do not name variablesconfigin admin routes as it shadowsexport const config = defineRouteConfig()
Admin routes are automatically protected and do not require explicit auth middleware
Files:
apps/medusa-be/src/api/admin/reviews/helpers.tsapps/medusa-be/src/api/admin/reviews/status/route.tsapps/medusa-be/src/api/admin/reviews/[id]/route.tsapps/medusa-be/src/api/admin/reviews/route.ts
apps/medusa-be/src/api/**/*.ts
📄 CodeRabbit inference engine (apps/medusa-be/CLAUDE.md)
apps/medusa-be/src/api/**/*.ts: Usereq.scope.resolve()to access container in routes
Colocatevalidators.tsandmiddlewares.tswith each route file in the same directory
UsevalidateAndTransformBody(Schema)middleware for POST/PUT request validation
UsevalidateAndTransformQuery(Schema)middleware for GET request query parameter validation
Usereq.validatedBodyin route handlers for type-safe access to validated request body
Files:
apps/medusa-be/src/api/admin/reviews/helpers.tsapps/medusa-be/src/api/admin/reviews/status/route.tsapps/medusa-be/src/api/admin-app-static.tsapps/medusa-be/src/api/admin/reviews/[id]/route.tsapps/medusa-be/src/api/admin/reviews/route.tsapps/medusa-be/src/api/store/products/[id]/reviews/route.tsapps/medusa-be/src/api/store/reviews/helpers.tsapps/medusa-be/src/api/review-normalizers.ts
apps/medusa-be/src/api/**/*.{ts,js}
📄 CodeRabbit inference engine (AGENTS.md)
Medusa backend API endpoints should be organized in the apps/medusa-be/src/api/ directory
Files:
apps/medusa-be/src/api/admin/reviews/helpers.tsapps/medusa-be/src/api/admin/reviews/status/route.tsapps/medusa-be/src/api/admin-app-static.tsapps/medusa-be/src/api/admin/reviews/[id]/route.tsapps/medusa-be/src/api/admin/reviews/route.tsapps/medusa-be/src/api/store/products/[id]/reviews/route.tsapps/medusa-be/src/api/store/reviews/helpers.tsapps/medusa-be/src/api/review-normalizers.ts
apps/medusa-be/src/modules/*/service.ts
📄 CodeRabbit inference engine (apps/medusa-be/CLAUDE.md)
apps/medusa-be/src/modules/*/service.ts: ExtendMedusaServicein module services for automatic CRUD methods
Callsuper(container, options)in module service constructors; do not usesuper(...arguments)
Implement rate limiting and token management in service layer, not in HTTP client
Use workflows for cross-module orchestration; do not use Query/Link in module service constructors
Use Query and Link patterns to access other modules from services instead of direct imports
Files:
apps/medusa-be/src/modules/product-review/service.tsapps/medusa-be/src/modules/workflow-queue/service.tsapps/medusa-be/src/modules/resend/service.ts
apps/medusa-be/src/admin/**/*
📄 CodeRabbit inference engine (CLAUDE.md)
Place admin panel customizations under apps/medusa-be/src/admin
Files:
apps/medusa-be/src/admin/routes/reviews/[id]/page.tsxapps/medusa-be/src/admin/lib/reviews.ts
apps/medusa-be/src/admin/**/*.{ts,tsx}
📄 CodeRabbit inference engine (apps/medusa-be/CLAUDE.md)
apps/medusa-be/src/admin/**/*.{ts,tsx}: Useimport.meta.env.VITE_*for public env vars in React admin app; no secret env vars
Useimport.meta.env.DEVandimport.meta.env.PRODfor environment detection in admin app
Files:
apps/medusa-be/src/admin/routes/reviews/[id]/page.tsxapps/medusa-be/src/admin/lib/reviews.ts
apps/medusa-be/src/admin/**/*.{ts,js}
📄 CodeRabbit inference engine (AGENTS.md)
Medusa backend admin panel customizations should be organized in the apps/medusa-be/src/admin/ directory
Files:
apps/medusa-be/src/admin/lib/reviews.ts
apps/medusa-be/src/scripts/**/*.ts
📄 CodeRabbit inference engine (apps/medusa-be/CLAUDE.md)
apps/medusa-be/src/scripts/**/*.ts: Usemedusa exec ./path/to/script.ts [args]to run one-off scripts instead of creating HTTP endpoints
Use script patternnpx medusa exec ./src/scripts/startup.tsin startup hooks
Use destructive operations inmedusa execscripts, never in unprotected GET endpoints
Files:
apps/medusa-be/src/scripts/herbatica-xml-utils.tsapps/medusa-be/src/scripts/herbatica-reviews-seed.ts
apps/medusa-be/src/jobs/**/*
📄 CodeRabbit inference engine (CLAUDE.md)
Place background jobs under apps/medusa-be/src/jobs
Files:
apps/medusa-be/src/jobs/workflow-queue-runner.ts
apps/medusa-be/src/jobs/**/*.ts
📄 CodeRabbit inference engine (apps/medusa-be/CLAUDE.md)
apps/medusa-be/src/jobs/**/*.ts: Usecontainer.resolve()to access services in jobs and loaders
Lock overlapping background jobs to prevent concurrent conflicts
Use locking module'sexecute()method with timeout and TTL for job synchronization
Handle locking timeout errors by checking if error message includes 'Timed-out'
Do not place test files insrc/jobs/__tests__/as Medusa loads allsrc/jobs/files at runtime
Files:
apps/medusa-be/src/jobs/workflow-queue-runner.ts
apps/medusa-be/src/jobs/**/*.{ts,js}
📄 CodeRabbit inference engine (AGENTS.md)
Medusa backend background jobs should be organized in the apps/medusa-be/src/jobs/ directory
Files:
apps/medusa-be/src/jobs/workflow-queue-runner.ts
🧠 Learnings (4)
📚 Learning: 2026-02-25T14:46:02.729Z
Learnt from: redeyecz
Repo: TechsioCZ/new-engine PR: 335
File: apps/zane-operator/src/db.ts:205-207
Timestamp: 2026-02-25T14:46:02.729Z
Learning: Enforce PostgreSQL 18+ as the minimum version across docker-compose files. Since the repo uses postgres:18.1-alpine (evidence in docker-compose.yaml), ensure all docker-compose service images for PostgreSQL use 18.1-alpine or newer. When reviewing, look for postgres images with a tag below 18 (e.g., postgres:<older-version>) and update to 18.1-alpine or a newer compatible tag. This guideline applies to all docker-compose YAML files that define PostgreSQL services.
Applied to files:
docker-compose.yaml
📚 Learning: 2026-05-18T16:32:35.366Z
Learnt from: redeyecz
Repo: TechsioCZ/new-engine PR: 409
File: apps/medusa-be/src/modules/producer/migrations/Migration20260518122326.ts:9-35
Timestamp: 2026-05-18T16:32:35.366Z
Learning: In `apps/medusa-be` MikroORM migration files under `src/modules/**/migrations/`, keep SQL schema-agnostic: do not explicitly qualify tables/indexes with a schema prefix (e.g., avoid `
Applied to files:
apps/medusa-be/src/modules/workflow-queue/migrations/Migration20260610080000.tsapps/medusa-be/src/modules/product-review/migrations/Migration20260610090000.ts
📚 Learning: 2025-12-16T19:45:17.746Z
Learnt from: BleedingDev
Repo: NMIT-WR/new-engine PR: 207
File: libs/ui/src/molecules/select.tsx:50-50
Timestamp: 2025-12-16T19:45:17.746Z
Learning: When reviewing Tailwind classes in TSX/TS files, prefer using square brackets for arbitrary CSS values and complex expressions. Specifically: - Do not use the parentheses syntax (z-(--z-index)) for anything beyond simple CSS variable references; this syntax auto-wraps in var() and cannot handle calc or complex functions. - Use the square brackets syntax (e.g., h-[calc(var(--available-height)-var(--spacing-content))]) for calc expressions, var with calc, and any complex CSS expressions. This rule applies broadly to Tailwind v4 usage in TSX code across the project.
Applied to files:
apps/medusa-be/src/admin/routes/reviews/[id]/page.tsx
📚 Learning: 2026-05-07T12:06:55.558Z
Learnt from: redeyecz
Repo: TechsioCZ/new-engine PR: 375
File: apps/medusa-be/src/admin/widgets/order-payment-reminder.tsx:3-11
Timestamp: 2026-05-07T12:06:55.558Z
Learning: In Medusa admin code under `apps/medusa-be/src/admin/` (admin widgets/routes), UI components must be imported from `medusajs/ui` (the Medusa admin UI kit). Do not apply the project-wide `libs/ui/atoms/*` and `libs/ui/molecules/*` import conventions to these files, and never flag `medusajs/ui` imports in this admin directory as violating the `libs/ui` convention.
Applied to files:
apps/medusa-be/src/admin/routes/reviews/[id]/page.tsx
🪛 ast-grep (0.43.0)
apps/medusa-be/src/scripts/herbatica-xml-utils.ts
[warning] 77-77: Regular expression constructed from variable input detected. This can lead to Regular Expression Denial of Service (ReDoS) attacks if the variable contains malicious patterns. Use libraries like 'recheck' to validate regex safety or use static patterns.
Context: new RegExp(<${escapedTag}(\\s[^>]*)?>([\\s\\S]*?)<\\/${escapedTag}>, "g")
Note: [CWE-1333] Inefficient Regular Expression Complexity
(regexp-from-variable)
[warning] 95-95: Regular expression constructed from variable input detected. This can lead to Regular Expression Denial of Service (ReDoS) attacks if the variable contains malicious patterns. Use libraries like 'recheck' to validate regex safety or use static patterns.
Context: new RegExp(<${escapedTag}(?:\\s[^>]*)?>([\\s\\S]*?)<\\/${escapedTag}>)
Note: [CWE-1333] Inefficient Regular Expression Complexity
(regexp-from-variable)
🔇 Additional comments (32)
apps/medusa-be/src/scripts/herbatica-xml-utils.ts (2)
72-78: LGTM!Also applies to: 95-96
1-70: LGTM!Also applies to: 100-124
apps/medusa-be/src/scripts/herbatica-reviews-seed.ts (2)
1-13: LGTM!Also applies to: 49-68, 163-176, 278-287, 313-324
15-47: LGTM!Also applies to: 70-138, 140-161, 194-259, 329-346
.env.docker (1)
78-78: LGTM!docker-compose.yaml (1)
29-34: LGTM!Also applies to: 43-43
apps/medusa-be/src/api/admin-app-static.ts (1)
1-85: LGTM!apps/medusa-be/src/modules/workflow-queue/index.ts (1)
4-8: LGTM!apps/medusa-be/src/modules/workflow-queue/migrations/Migration20260610080000.ts (1)
1-1: LGTM!Also applies to: 17-19
apps/medusa-be/src/workflows/product-review/types.ts (1)
19-34: LGTM!apps/medusa-be/src/workflows/product-review/steps/update-review.ts (1)
6-29: LGTM!apps/medusa-be/src/workflows/product-review/workflows/update-review.ts (1)
8-15: LGTM!apps/medusa-be/src/workflows/product-review/steps/update-review-status.ts (1)
6-31: LGTM!apps/medusa-be/src/workflows/product-review/workflows/update-review-status.ts (1)
8-15: LGTM!apps/medusa-be/src/workflows/send-product-review-request.ts (2)
166-176: LGTM!
288-292: LGTM!apps/medusa-be/src/modules/resend/service.ts (1)
80-99: LGTM!Also applies to: 180-189
apps/medusa-be/src/subscriber-helpers/product-review-request-on-payment/helper.ts (1)
46-65: LGTM!Also applies to: 145-151, 160-164
apps/medusa-be/src/utils/order-review-requests.ts (1)
26-131: LGTM!apps/medusa-be/src/utils/product-review-request-queue.ts (1)
62-70: LGTM!Also applies to: 83-87
apps/medusa-be/src/utils/workflow-queue-registry.ts (1)
28-33: LGTM!apps/medusa-be/src/jobs/workflow-queue-runner.ts (1)
27-35: LGTM!Also applies to: 105-125
apps/medusa-be/src/modules/workflow-queue/service.ts (1)
33-40: Fix PostgreSQL parameter placeholders in workflow queue query
File: apps/medusa-be/src/modules/workflow-queue/service.ts (lines 33-40)const rows = await manager.execute<IdRow[]>( `select "id" from "workflow_queue_item" where "workflow" = ? and "arguments"->>'order_id' = ? and "deleted_at" is null limit 1`, [workflow, orderId]PostgreSQL (via TypeORM/pg) expects positional placeholders like
$1,$2—?is for other drivers and is not generally accepted by PostgreSQL.
- Update the query to use
$1forworkflowand$2fororderId(keeping the parameters array order aligned).- Check how
manager.executeformats placeholders in this codebase (search for othermanager.execute/raw SQL calls to confirm the convention).apps/medusa-be/src/modules/product-review/service.ts (1)
25-42: LGTM!apps/medusa-be/src/api/admin/reviews/[id]/route.ts (1)
16-28: LGTM!Also applies to: 30-59
apps/medusa-be/src/api/store/products/[id]/reviews/route.ts (1)
11-43: LGTM!apps/medusa-be/src/api/review-normalizers.ts (1)
78-99: LGTM!apps/medusa-be/src/api/admin/reviews/helpers.ts (1)
3-6: LGTM!Also applies to: 25-27
apps/medusa-be/src/api/admin/reviews/route.ts (1)
3-3: LGTM!Also applies to: 30-40
apps/medusa-be/src/api/admin/reviews/status/route.ts (1)
15-28: LGTM!apps/medusa-be/src/admin/lib/reviews.ts (1)
34-43: LGTM!apps/medusa-be/src/admin/routes/reviews/[id]/page.tsx (1)
53-60: LGTM!Also applies to: 72-78, 194-196
Summary by CodeRabbit
New Features
Chores