Skip to content

Feat/reviews - #437

Merged
KaiUweCZE merged 12 commits into
masterfrom
feat/reviews
Jun 10, 2026
Merged

Feat/reviews#437
KaiUweCZE merged 12 commits into
masterfrom
feat/reviews

Conversation

@tomas-cm1

@tomas-cm1 tomas-cm1 commented Jun 10, 2026

Copy link
Copy Markdown
Collaborator

Summary by CodeRabbit

  • New Features

    • Product review system: customers can submit reviews with rating, title and edit via admin UI; admins can view, search, filter, edit and bulk-update review status.
    • Automated review-request emails scheduled after order payment; public endpoints to list product reviews.
    • Import reviews from external XML feeds and a seed script to load Herbatica reviews.
    • Review tokens and queued workflows for reliable delivery and processing.
  • Chores

    • Added environment/config keys and CLI seed script entry for reviews; workflow queue runner configuration.

@semanticdiff-com

semanticdiff-com Bot commented Jun 10, 2026

Copy link
Copy Markdown

Review changes with  SemanticDiff

Changed Files
File Status
  apps/medusa-be/src/modules/resend/service.ts  18% smaller
  apps/medusa-be/src/api/middlewares.ts  15% smaller
  .env.docker Unsupported file format
  apps/medusa-be/medusa-config.ts  0% smaller
  apps/medusa-be/package.json  0% smaller
  apps/medusa-be/src/admin/lib/reviews.ts  0% smaller
  apps/medusa-be/src/admin/routes/reviews/[id]/page.tsx  0% smaller
  apps/medusa-be/src/admin/routes/reviews/page.tsx  0% smaller
  apps/medusa-be/src/api/admin-app-static.ts  0% smaller
  apps/medusa-be/src/api/admin/reviews/[id]/route.ts  0% smaller
  apps/medusa-be/src/api/admin/reviews/helpers.ts  0% smaller
  apps/medusa-be/src/api/admin/reviews/middlewares.ts  0% smaller
  apps/medusa-be/src/api/admin/reviews/route.ts  0% smaller
  apps/medusa-be/src/api/admin/reviews/status/route.ts  0% smaller
  apps/medusa-be/src/api/admin/reviews/validators.ts  0% smaller
  apps/medusa-be/src/api/review-normalizers.ts  0% smaller
  apps/medusa-be/src/api/store/products/[id]/reviews/route.ts  0% smaller
  apps/medusa-be/src/api/store/products/[id]/reviews/validators.ts  0% smaller
  apps/medusa-be/src/api/store/reviews/helpers.ts  0% smaller
  apps/medusa-be/src/api/store/reviews/middlewares.ts  0% smaller
  apps/medusa-be/src/api/store/reviews/route.ts  0% smaller
  apps/medusa-be/src/api/store/reviews/validators.ts  0% smaller
  apps/medusa-be/src/jobs/workflow-queue-runner.ts  0% smaller
  apps/medusa-be/src/links/customer-review.ts  0% smaller
  apps/medusa-be/src/links/product-review.ts  0% smaller
  apps/medusa-be/src/modules/product-review/index.ts  0% smaller
  apps/medusa-be/src/modules/product-review/migrations/.snapshot-product-review.json  0% smaller
  apps/medusa-be/src/modules/product-review/migrations/Migration20260525120000.ts  0% smaller
  apps/medusa-be/src/modules/product-review/migrations/Migration20260610090000.ts  0% smaller
  apps/medusa-be/src/modules/product-review/models/review-token.ts  0% smaller
  apps/medusa-be/src/modules/product-review/models/review.ts  0% smaller
  apps/medusa-be/src/modules/product-review/service.ts  0% smaller
  apps/medusa-be/src/modules/resend/templates.ts  0% smaller
  apps/medusa-be/src/modules/workflow-queue/index.ts  0% smaller
  apps/medusa-be/src/modules/workflow-queue/migrations/Migration20260610080000.ts  0% smaller
  apps/medusa-be/src/modules/workflow-queue/migrations/Migration20260610100000.ts  0% smaller
  apps/medusa-be/src/modules/workflow-queue/models/workflow-queue-item.ts  0% smaller
  apps/medusa-be/src/modules/workflow-queue/service.ts  0% smaller
  apps/medusa-be/src/scripts/herbatica-category-export.ts  0% smaller
  apps/medusa-be/src/scripts/herbatica-reviews-seed.ts  0% smaller
  apps/medusa-be/src/scripts/herbatica-seed-config.ts  0% smaller
  apps/medusa-be/src/scripts/herbatica-seed.ts  0% smaller
  apps/medusa-be/src/scripts/herbatica-xml-utils.ts  0% smaller
  apps/medusa-be/src/subscriber-helpers/product-review-request-on-payment/helper.ts  0% smaller
  apps/medusa-be/src/subscribers/product-review-request-on-payment.ts  0% smaller
  apps/medusa-be/src/utils/order-review-requests.ts  0% smaller
  apps/medusa-be/src/utils/product-review-request-queue.ts  0% smaller
  apps/medusa-be/src/utils/workflow-queue-registry.ts  0% smaller
  apps/medusa-be/src/workflows/product-review/steps/create-review.ts  0% smaller
  apps/medusa-be/src/workflows/product-review/steps/mark-review-token-used.ts  0% smaller
  apps/medusa-be/src/workflows/product-review/steps/update-review-status.ts  0% smaller
  apps/medusa-be/src/workflows/product-review/steps/update-review.ts  0% smaller
  apps/medusa-be/src/workflows/product-review/types.ts  0% smaller
  apps/medusa-be/src/workflows/product-review/workflows/create-review.ts  0% smaller
  apps/medusa-be/src/workflows/product-review/workflows/update-review-status.ts  0% smaller
  apps/medusa-be/src/workflows/product-review/workflows/update-review.ts  0% smaller
  apps/medusa-be/src/workflows/send-product-review-request.ts  0% smaller
  apps/medusa-be/src/workflows/workflow-queue/steps/delete-workflow-queue-item.ts  0% smaller
  docker-compose.yaml  0% smaller

@vercel

vercel Bot commented Jun 10, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
new-engine-ui-storybook Ready Ready Preview, Comment Jun 10, 2026 11:29am

@coderabbitai

coderabbitai Bot commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@tomas-cm1, we couldn't start this review because you've reached your PR review rate limit.

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 @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

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 configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: ecd8a855-074b-4620-a36c-41f31b087d57

📥 Commits

Reviewing files that changed from the base of the PR and between ea821dd and 9997472.

📒 Files selected for processing (7)
  • apps/medusa-be/src/api/store/products/[id]/reviews/route.ts
  • apps/medusa-be/src/modules/product-review/service.ts
  • apps/medusa-be/src/modules/workflow-queue/migrations/Migration20260610080000.ts
  • apps/medusa-be/src/modules/workflow-queue/migrations/Migration20260610100000.ts
  • apps/medusa-be/src/modules/workflow-queue/models/workflow-queue-item.ts
  • apps/medusa-be/src/modules/workflow-queue/service.ts
  • apps/medusa-be/src/utils/product-review-request-queue.ts

Walkthrough

Adds 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.

Changes

Product Review Core & Admin Management

Layer / File(s) Summary
Product Review Module, Models & Links
apps/medusa-be/src/modules/product-review/*, apps/medusa-be/src/links/*
Defines product_review and workflow_queue modules, Review and ReviewToken models, and read-only links to Product and Customer modules.
Database Schema & Migrations
apps/medusa-be/src/modules/product-review/migrations/*
MikroORM migrations and snapshot for review and review_token tables with partial indexes, soft-delete, and check constraints for rating/status.
API Response Normalizers & Type Definitions
apps/medusa-be/src/api/review-normalizers.ts
Helpers to build admin/store filters, escape ilike patterns, normalise ordering, and shape admin/public review payloads.
Admin API Validators & Endpoints
apps/medusa-be/src/api/admin/reviews/*
Zod schemas, route middlewares, and handlers for listing, retrieving, updating reviews and bulk status updates with product enrichment.
Admin Client Library & Cache Keys
apps/medusa-be/src/admin/lib/reviews.ts
Typed client wrappers (listReviews, retrieveReview, updateReview, updateReviewStatus) and React Query cache key helpers.
Admin UI: Review List & Detail Pages
apps/medusa-be/src/admin/routes/reviews/*
Reviews list page with search/status filters, pagination and bulk actions; detail page with edit drawer and mutation handling.

Store Reviews API

Layer / File(s) Summary
Store Review Validators & Helper Functions
apps/medusa-be/src/api/store/reviews/validators.ts, apps/medusa-be/src/api/store/reviews/helpers.ts
Zod schema for review creation, token/customer resolution, token usability checks, duplicate-prevention and product/customer existence checks.
Store Review API Endpoints
apps/medusa-be/src/api/store/reviews/route.ts, apps/medusa-be/src/api/store/products/[id]/reviews/route.ts
POST /store/reviews accepts authenticated or token-based submissions; GET /store/products/:id/reviews returns approved reviews with count/summary.

Review Request Workflow & Workflow Queue System

Layer / File(s) Summary
Workflow Queue Module & Infrastructure
apps/medusa-be/src/modules/workflow-queue/*
Module, model, service and migration for persistent queue items and queries for queued workflows.
Review & Queue Workflow Definitions and Steps
apps/medusa-be/src/workflows/product-review/*, apps/medusa-be/src/workflows/*
Steps and workflows for creating/updating reviews, marking tokens used, update-status, sending product-review-request emails and deleting queue items.
Order Eligibility & Review Request Scheduling
apps/medusa-be/src/utils/order-review-requests.ts, apps/medusa-be/src/utils/product-review-request-queue.ts
Logic to determine paid orders, compute delay/run times, and idempotently schedule SEND_PRODUCT_REVIEW_REQUEST queue items.
Payment Subscriber & Workflow Queue Registry
apps/medusa-be/src/subscribers/*, apps/medusa-be/src/subscriber-helpers/*, apps/medusa-be/src/utils/workflow-queue-registry.ts
Subscriber resolves order IDs from payment events and schedules review requests; registry maps queue names to runners with input validation.
Workflow Queue Job Runner & Execution
apps/medusa-be/src/jobs/workflow-queue-runner.ts
Cron job that fetches due queue items and executes corresponding workflow runners under a distributed lock with per-item error isolation.

Supporting Features & Configuration

Layer / File(s) Summary
Admin Static Asset Serving
apps/medusa-be/src/api/admin-app-static.ts
Middleware to serve the built admin SPA with path-normalisation and path-traversal protection and SPA index fallback.
Email Template Configuration for Review Requests
apps/medusa-be/src/modules/resend/*
Extends Resend template system types and adds product-review-request template definition and variable handling.
Herbatica XML Parsing & Loading Utilities
apps/medusa-be/src/scripts/herbatica-xml-utils.ts
Lightweight XML decoding, element extraction and source-loading utilities used by seed scripts.
Refactor Existing Herbatica Scripts to Use Utilities
apps/medusa-be/src/scripts/herbatica-category-export.ts
Category export script reuses/exports XML utilities instead of local implementations.
Herbatica Reviews Import Script
apps/medusa-be/src/scripts/herbatica-reviews-seed.ts, apps/medusa-be/src/scripts/herbatica-seed.ts, apps/medusa-be/src/scripts/herbatica-seed-config.ts
Seed script to parse Herbatica reviews XML, match to internal products via variant/SKU/EAN, deduplicate, batch-create reviews; main seed updated to optionally import reviews; new HERBATICA_REVIEWS_XML_PATH env const.
Application Configuration & Middleware Wiring
apps/medusa-be/medusa-config.ts, apps/medusa-be/src/api/middlewares.ts, .env.docker, docker-compose.yaml, apps/medusa-be/package.json
Registers new modules, wires admin/store review middlewares and admin static serving, adds seed npm script, and exposes environment variables for review requests and Herbatica feed paths.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/reviews
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch feat/reviews

@greptile-apps

greptile-apps Bot commented Jun 10, 2026

Copy link
Copy Markdown

Greptile Summary

This 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.

  • Store API: POST /store/reviews accepts authenticated or token-based submissions with rating, title, and content; GET /store/products/:id/reviews returns paginated approved reviews with an average-rating summary.
  • Admin API: CRUD endpoints with search/filter, bulk status update, and admin UI pages for listing and editing reviews.
  • Workflow queue: A generic scheduled-job queue (workflow_queue_item) drives delayed review-request emails with deduplication via email-log check and per-order queue record; the queue runner now correctly caps fetches to a configurable batch size (500 default).
  • Herbatica seed: One-time XML import matching reviews to products via SKU/GTIN/variant metadata lookups, batched into groups of 100.

Confidence Score: 4/5

Safe 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

Filename Overview
apps/medusa-be/src/api/store/reviews/helpers.ts Core helper for token-based review flow; synthetic customer ID for null-customer tokens creates a gap in the duplicate-review guard for returning customers.
apps/medusa-be/src/api/store/reviews/route.ts Store POST /reviews endpoint — validation, token lookup, and workflow dispatch look correct; duplicate-review guard relies on the customer ID strategy in helpers.ts.
apps/medusa-be/src/api/store/products/[id]/reviews/route.ts Public review listing with summary; two-query approach for average rating has a TOCTOU count/rating inconsistency and loads all approved reviews for the product on each request.
apps/medusa-be/src/workflows/send-product-review-request.ts Review-request email workflow; token expiry (90-day default) is now set; step ordering (send then delete) retains the duplicate-email risk on queue-delete failure flagged in previous review.
apps/medusa-be/src/jobs/workflow-queue-runner.ts Queue runner now uses a configurable batch size (default 500) with locking; previously unbounded fetch is addressed.
apps/medusa-be/src/scripts/herbatica-reviews-seed.ts One-time XML import script; loads all variants and all existing Herbatica reviews into memory without pagination, which is fine for small catalogs but will degrade on large stores.
apps/medusa-be/src/modules/product-review/models/review.ts Review model with appropriate DB constraints (rating range check, status enum, unique customer+product index).
apps/medusa-be/src/api/review-normalizers.ts Normalizers for admin and public review responses; admin path enriches with product data, public path strips customer ID and status before returning.

Fix All in Codex

Reviews (5): Last reviewed commit: "fix: remove review summary batch setting" | Re-trigger Greptile

Comment thread apps/medusa-be/src/api/store/products/[id]/reviews/route.ts Outdated
Comment thread apps/medusa-be/src/utils/product-review-request-queue.ts
Comment thread apps/medusa-be/src/api/admin/reviews/status/route.ts Outdated
Comment thread apps/medusa-be/src/workflows/send-product-review-request.ts
Comment thread apps/medusa-be/src/utils/order-review-requests.ts Outdated
Comment thread apps/medusa-be/src/jobs/workflow-queue-runner.ts
Comment thread apps/medusa-be/src/workflows/send-product-review-request.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

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 win

Validate template variable values before type casting.

The template variable values are cast to TemplateVariableValue without 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

📥 Commits

Reviewing files that changed from the base of the PR and between 8c80ca0 and e23dd38.

📒 Files selected for processing (54)
  • .env.docker
  • apps/medusa-be/medusa-config.ts
  • apps/medusa-be/package.json
  • apps/medusa-be/src/admin/lib/reviews.ts
  • apps/medusa-be/src/admin/routes/reviews/[id]/page.tsx
  • apps/medusa-be/src/admin/routes/reviews/page.tsx
  • apps/medusa-be/src/api/admin-app-static.ts
  • apps/medusa-be/src/api/admin/reviews/[id]/route.ts
  • apps/medusa-be/src/api/admin/reviews/helpers.ts
  • apps/medusa-be/src/api/admin/reviews/middlewares.ts
  • apps/medusa-be/src/api/admin/reviews/route.ts
  • apps/medusa-be/src/api/admin/reviews/status/route.ts
  • apps/medusa-be/src/api/admin/reviews/validators.ts
  • apps/medusa-be/src/api/middlewares.ts
  • apps/medusa-be/src/api/review-normalizers.ts
  • apps/medusa-be/src/api/store/products/[id]/reviews/route.ts
  • apps/medusa-be/src/api/store/products/[id]/reviews/validators.ts
  • apps/medusa-be/src/api/store/reviews/helpers.ts
  • apps/medusa-be/src/api/store/reviews/middlewares.ts
  • apps/medusa-be/src/api/store/reviews/route.ts
  • apps/medusa-be/src/api/store/reviews/validators.ts
  • apps/medusa-be/src/jobs/workflow-queue-runner.ts
  • apps/medusa-be/src/links/customer-review.ts
  • apps/medusa-be/src/links/product-review.ts
  • apps/medusa-be/src/modules/product-review/index.ts
  • apps/medusa-be/src/modules/product-review/migrations/.snapshot-product-review.json
  • apps/medusa-be/src/modules/product-review/migrations/Migration20260525120000.ts
  • apps/medusa-be/src/modules/product-review/migrations/Migration20260610090000.ts
  • apps/medusa-be/src/modules/product-review/models/review-token.ts
  • apps/medusa-be/src/modules/product-review/models/review.ts
  • apps/medusa-be/src/modules/product-review/service.ts
  • apps/medusa-be/src/modules/resend/service.ts
  • apps/medusa-be/src/modules/resend/templates.ts
  • apps/medusa-be/src/modules/workflow-queue/index.ts
  • apps/medusa-be/src/modules/workflow-queue/migrations/Migration20260610080000.ts
  • apps/medusa-be/src/modules/workflow-queue/models/workflow-queue-item.ts
  • apps/medusa-be/src/modules/workflow-queue/service.ts
  • apps/medusa-be/src/scripts/herbatica-category-export.ts
  • apps/medusa-be/src/scripts/herbatica-reviews-seed.ts
  • apps/medusa-be/src/scripts/herbatica-seed-config.ts
  • apps/medusa-be/src/scripts/herbatica-seed.ts
  • apps/medusa-be/src/scripts/herbatica-xml-utils.ts
  • apps/medusa-be/src/subscriber-helpers/product-review-request-on-payment/helper.ts
  • apps/medusa-be/src/subscribers/product-review-request-on-payment.ts
  • apps/medusa-be/src/utils/order-review-requests.ts
  • apps/medusa-be/src/utils/product-review-request-queue.ts
  • apps/medusa-be/src/utils/workflow-queue-registry.ts
  • apps/medusa-be/src/workflows/product-review/steps/create-review.ts
  • apps/medusa-be/src/workflows/product-review/steps/mark-review-token-used.ts
  • apps/medusa-be/src/workflows/product-review/types.ts
  • apps/medusa-be/src/workflows/product-review/workflows/create-review.ts
  • apps/medusa-be/src/workflows/send-product-review-request.ts
  • apps/medusa-be/src/workflows/workflow-queue/steps/delete-workflow-queue-item.ts
  • docker-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.ts
  • apps/medusa-be/src/modules/workflow-queue/index.ts
  • apps/medusa-be/src/modules/product-review/migrations/Migration20260610090000.ts
  • apps/medusa-be/src/modules/workflow-queue/migrations/Migration20260610080000.ts
  • apps/medusa-be/src/modules/product-review/models/review-token.ts
  • apps/medusa-be/src/modules/product-review/migrations/Migration20260525120000.ts
  • apps/medusa-be/src/modules/product-review/models/review.ts
  • apps/medusa-be/src/modules/workflow-queue/models/workflow-queue-item.ts
  • apps/medusa-be/src/modules/workflow-queue/service.ts
  • apps/medusa-be/src/modules/product-review/service.ts
  • apps/medusa-be/src/modules/resend/templates.ts
  • apps/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}: Run npx tsc --noEmit for typechecking before committing
Always use braces around conditional blocks, even for single statements; Biome will expand them
Declare one variable per const/let statement, 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 as unknown when 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
Use Modules.* and ContainerRegistrationKeys.* 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 use as Type without prior validation

Files:

  • apps/medusa-be/src/modules/product-review/index.ts
  • apps/medusa-be/src/modules/workflow-queue/index.ts
  • apps/medusa-be/src/links/customer-review.ts
  • apps/medusa-be/src/api/store/reviews/middlewares.ts
  • apps/medusa-be/src/links/product-review.ts
  • apps/medusa-be/src/workflows/product-review/steps/create-review.ts
  • apps/medusa-be/src/modules/product-review/migrations/Migration20260610090000.ts
  • apps/medusa-be/src/modules/workflow-queue/migrations/Migration20260610080000.ts
  • apps/medusa-be/src/modules/product-review/models/review-token.ts
  • apps/medusa-be/src/modules/product-review/migrations/Migration20260525120000.ts
  • apps/medusa-be/src/workflows/workflow-queue/steps/delete-workflow-queue-item.ts
  • apps/medusa-be/src/workflows/product-review/types.ts
  • apps/medusa-be/src/modules/product-review/models/review.ts
  • apps/medusa-be/src/workflows/product-review/steps/mark-review-token-used.ts
  • apps/medusa-be/src/api/store/products/[id]/reviews/validators.ts
  • apps/medusa-be/src/modules/workflow-queue/models/workflow-queue-item.ts
  • apps/medusa-be/src/api/admin-app-static.ts
  • apps/medusa-be/src/workflows/send-product-review-request.ts
  • apps/medusa-be/src/modules/workflow-queue/service.ts
  • apps/medusa-be/src/api/store/reviews/validators.ts
  • apps/medusa-be/src/workflows/product-review/workflows/create-review.ts
  • apps/medusa-be/src/scripts/herbatica-seed-config.ts
  • apps/medusa-be/src/api/admin/reviews/status/route.ts
  • apps/medusa-be/src/api/admin/reviews/route.ts
  • apps/medusa-be/medusa-config.ts
  • apps/medusa-be/src/api/admin/reviews/helpers.ts
  • apps/medusa-be/src/modules/product-review/service.ts
  • apps/medusa-be/src/modules/resend/templates.ts
  • apps/medusa-be/src/api/admin/reviews/validators.ts
  • apps/medusa-be/src/api/admin/reviews/middlewares.ts
  • apps/medusa-be/src/api/middlewares.ts
  • apps/medusa-be/src/api/admin/reviews/[id]/route.ts
  • apps/medusa-be/src/api/store/products/[id]/reviews/route.ts
  • apps/medusa-be/src/api/store/reviews/route.ts
  • apps/medusa-be/src/utils/workflow-queue-registry.ts
  • apps/medusa-be/src/jobs/workflow-queue-runner.ts
  • apps/medusa-be/src/subscribers/product-review-request-on-payment.ts
  • apps/medusa-be/src/utils/product-review-request-queue.ts
  • apps/medusa-be/src/admin/routes/reviews/[id]/page.tsx
  • apps/medusa-be/src/admin/lib/reviews.ts
  • apps/medusa-be/src/api/review-normalizers.ts
  • apps/medusa-be/src/modules/resend/service.ts
  • apps/medusa-be/src/admin/routes/reviews/page.tsx
  • apps/medusa-be/src/scripts/herbatica-reviews-seed.ts
  • apps/medusa-be/src/subscriber-helpers/product-review-request-on-payment/helper.ts
  • apps/medusa-be/src/scripts/herbatica-xml-utils.ts
  • apps/medusa-be/src/utils/order-review-requests.ts
  • apps/medusa-be/src/api/store/reviews/helpers.ts
  • apps/medusa-be/src/scripts/herbatica-category-export.ts
  • apps/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.ts
  • apps/medusa-be/src/modules/workflow-queue/index.ts
  • apps/medusa-be/src/links/customer-review.ts
  • apps/medusa-be/src/api/store/reviews/middlewares.ts
  • apps/medusa-be/src/links/product-review.ts
  • apps/medusa-be/src/workflows/product-review/steps/create-review.ts
  • apps/medusa-be/src/modules/product-review/migrations/Migration20260610090000.ts
  • apps/medusa-be/src/modules/workflow-queue/migrations/Migration20260610080000.ts
  • apps/medusa-be/src/modules/product-review/models/review-token.ts
  • apps/medusa-be/src/modules/product-review/migrations/Migration20260525120000.ts
  • apps/medusa-be/src/workflows/workflow-queue/steps/delete-workflow-queue-item.ts
  • apps/medusa-be/src/workflows/product-review/types.ts
  • apps/medusa-be/src/modules/product-review/models/review.ts
  • apps/medusa-be/src/workflows/product-review/steps/mark-review-token-used.ts
  • apps/medusa-be/src/api/store/products/[id]/reviews/validators.ts
  • apps/medusa-be/src/modules/workflow-queue/models/workflow-queue-item.ts
  • apps/medusa-be/src/api/admin-app-static.ts
  • apps/medusa-be/src/workflows/send-product-review-request.ts
  • apps/medusa-be/src/modules/workflow-queue/service.ts
  • apps/medusa-be/src/api/store/reviews/validators.ts
  • apps/medusa-be/src/workflows/product-review/workflows/create-review.ts
  • apps/medusa-be/src/scripts/herbatica-seed-config.ts
  • apps/medusa-be/src/api/admin/reviews/status/route.ts
  • apps/medusa-be/src/api/admin/reviews/route.ts
  • apps/medusa-be/medusa-config.ts
  • apps/medusa-be/src/api/admin/reviews/helpers.ts
  • apps/medusa-be/src/modules/product-review/service.ts
  • apps/medusa-be/src/modules/resend/templates.ts
  • apps/medusa-be/src/api/admin/reviews/validators.ts
  • apps/medusa-be/src/api/admin/reviews/middlewares.ts
  • apps/medusa-be/src/api/middlewares.ts
  • apps/medusa-be/src/api/admin/reviews/[id]/route.ts
  • apps/medusa-be/src/api/store/products/[id]/reviews/route.ts
  • apps/medusa-be/src/api/store/reviews/route.ts
  • apps/medusa-be/src/utils/workflow-queue-registry.ts
  • apps/medusa-be/src/jobs/workflow-queue-runner.ts
  • apps/medusa-be/src/subscribers/product-review-request-on-payment.ts
  • apps/medusa-be/src/utils/product-review-request-queue.ts
  • apps/medusa-be/src/admin/routes/reviews/[id]/page.tsx
  • apps/medusa-be/src/admin/lib/reviews.ts
  • apps/medusa-be/src/api/review-normalizers.ts
  • apps/medusa-be/src/modules/resend/service.ts
  • apps/medusa-be/src/admin/routes/reviews/page.tsx
  • apps/medusa-be/src/scripts/herbatica-reviews-seed.ts
  • apps/medusa-be/src/subscriber-helpers/product-review-request-on-payment/helper.ts
  • apps/medusa-be/src/scripts/herbatica-xml-utils.ts
  • apps/medusa-be/src/utils/order-review-requests.ts
  • apps/medusa-be/src/api/store/reviews/helpers.ts
  • apps/medusa-be/src/scripts/herbatica-category-export.ts
  • apps/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: Use const and explicit typing with dbService.sqlRaw<Type>() for SQL query results
Resolve logger using container.resolve<Logger>(ContainerRegistrationKeys.LOGGER)
Resolve Query using container.resolve<Query>(ContainerRegistrationKeys.QUERY)
Use Modules.LOCKING (not Modules.LOCK) to resolve locking services
Use Modules.CACHING (not Modules.CACHE) to resolve caching services
Throw MedusaError with appropriate type and message for error responses
Use MedusaError.Types.INVALID_DATA for 400 validation errors
Use MedusaError.Types.NOT_FOUND for 404 errors
Use MedusaError.Types.UNAUTHORIZED for 401 authentication errors
Use MedusaError.Types.NOT_ALLOWED for 400 permission errors
Use MedusaError.Types.DUPLICATE_ERROR for 422 duplicate entry errors
Use MedusaError.Types.CONFLICT for 409 conflict errors
Use caching module's computeKey() to generate stable cache keys from filters and pagination
Use caching module's get() with type assertion for cache retrieval
Use caching module's set() with TTL and tags for cache storage and bulk invalidation
Use caching module's clear() with tags to bulk-invalidate related cache entries
Always use Redis for caching in multi-container deployments instead of local variables
Batch operations using CHUNK_SIZE constant instead of unbounded loops

Files:

  • apps/medusa-be/src/modules/product-review/index.ts
  • apps/medusa-be/src/modules/workflow-queue/index.ts
  • apps/medusa-be/src/links/customer-review.ts
  • apps/medusa-be/src/api/store/reviews/middlewares.ts
  • apps/medusa-be/src/links/product-review.ts
  • apps/medusa-be/src/workflows/product-review/steps/create-review.ts
  • apps/medusa-be/src/modules/product-review/migrations/Migration20260610090000.ts
  • apps/medusa-be/src/modules/workflow-queue/migrations/Migration20260610080000.ts
  • apps/medusa-be/src/modules/product-review/models/review-token.ts
  • apps/medusa-be/src/modules/product-review/migrations/Migration20260525120000.ts
  • apps/medusa-be/src/workflows/workflow-queue/steps/delete-workflow-queue-item.ts
  • apps/medusa-be/src/workflows/product-review/types.ts
  • apps/medusa-be/src/modules/product-review/models/review.ts
  • apps/medusa-be/src/workflows/product-review/steps/mark-review-token-used.ts
  • apps/medusa-be/src/api/store/products/[id]/reviews/validators.ts
  • apps/medusa-be/src/modules/workflow-queue/models/workflow-queue-item.ts
  • apps/medusa-be/src/api/admin-app-static.ts
  • apps/medusa-be/src/workflows/send-product-review-request.ts
  • apps/medusa-be/src/modules/workflow-queue/service.ts
  • apps/medusa-be/src/api/store/reviews/validators.ts
  • apps/medusa-be/src/workflows/product-review/workflows/create-review.ts
  • apps/medusa-be/src/scripts/herbatica-seed-config.ts
  • apps/medusa-be/src/api/admin/reviews/status/route.ts
  • apps/medusa-be/src/api/admin/reviews/route.ts
  • apps/medusa-be/src/api/admin/reviews/helpers.ts
  • apps/medusa-be/src/modules/product-review/service.ts
  • apps/medusa-be/src/modules/resend/templates.ts
  • apps/medusa-be/src/api/admin/reviews/validators.ts
  • apps/medusa-be/src/api/admin/reviews/middlewares.ts
  • apps/medusa-be/src/api/middlewares.ts
  • apps/medusa-be/src/api/admin/reviews/[id]/route.ts
  • apps/medusa-be/src/api/store/products/[id]/reviews/route.ts
  • apps/medusa-be/src/api/store/reviews/route.ts
  • apps/medusa-be/src/utils/workflow-queue-registry.ts
  • apps/medusa-be/src/jobs/workflow-queue-runner.ts
  • apps/medusa-be/src/subscribers/product-review-request-on-payment.ts
  • apps/medusa-be/src/utils/product-review-request-queue.ts
  • apps/medusa-be/src/admin/lib/reviews.ts
  • apps/medusa-be/src/api/review-normalizers.ts
  • apps/medusa-be/src/modules/resend/service.ts
  • apps/medusa-be/src/scripts/herbatica-reviews-seed.ts
  • apps/medusa-be/src/subscriber-helpers/product-review-request-on-payment/helper.ts
  • apps/medusa-be/src/scripts/herbatica-xml-utils.ts
  • apps/medusa-be/src/utils/order-review-requests.ts
  • apps/medusa-be/src/api/store/reviews/helpers.ts
  • apps/medusa-be/src/scripts/herbatica-category-export.ts
  • apps/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.ts
  • 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/product-review/index.ts
  • apps/medusa-be/src/modules/workflow-queue/index.ts
  • apps/medusa-be/src/modules/product-review/migrations/Migration20260610090000.ts
  • apps/medusa-be/src/modules/workflow-queue/migrations/Migration20260610080000.ts
  • apps/medusa-be/src/modules/product-review/models/review-token.ts
  • apps/medusa-be/src/modules/product-review/migrations/Migration20260525120000.ts
  • apps/medusa-be/src/modules/product-review/models/review.ts
  • apps/medusa-be/src/modules/workflow-queue/models/workflow-queue-item.ts
  • apps/medusa-be/src/modules/workflow-queue/service.ts
  • apps/medusa-be/src/modules/product-review/service.ts
  • apps/medusa-be/src/modules/resend/templates.ts
  • apps/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.ts
  • apps/medusa-be/src/modules/workflow-queue/index.ts
  • apps/medusa-be/src/modules/product-review/migrations/Migration20260610090000.ts
  • apps/medusa-be/src/modules/workflow-queue/migrations/Migration20260610080000.ts
  • apps/medusa-be/src/modules/product-review/models/review-token.ts
  • apps/medusa-be/src/modules/product-review/migrations/Migration20260525120000.ts
  • apps/medusa-be/src/modules/product-review/models/review.ts
  • apps/medusa-be/src/modules/workflow-queue/models/workflow-queue-item.ts
  • apps/medusa-be/src/modules/workflow-queue/service.ts
  • apps/medusa-be/src/modules/product-review/service.ts
  • apps/medusa-be/src/modules/resend/templates.ts
  • apps/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.ts
  • apps/medusa-be/src/api/store/products/[id]/reviews/validators.ts
  • apps/medusa-be/src/api/admin-app-static.ts
  • apps/medusa-be/src/api/store/reviews/validators.ts
  • apps/medusa-be/src/api/admin/reviews/status/route.ts
  • apps/medusa-be/src/api/admin/reviews/route.ts
  • apps/medusa-be/src/api/admin/reviews/helpers.ts
  • apps/medusa-be/src/api/admin/reviews/validators.ts
  • apps/medusa-be/src/api/admin/reviews/middlewares.ts
  • apps/medusa-be/src/api/middlewares.ts
  • apps/medusa-be/src/api/admin/reviews/[id]/route.ts
  • apps/medusa-be/src/api/store/products/[id]/reviews/route.ts
  • apps/medusa-be/src/api/store/reviews/route.ts
  • apps/medusa-be/src/api/review-normalizers.ts
  • apps/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: Use req.scope.resolve() to access container in routes
Colocate validators.ts and middlewares.ts with each route file in the same directory
Use validateAndTransformBody(Schema) middleware for POST/PUT request validation
Use validateAndTransformQuery(Schema) middleware for GET request query parameter validation
Use req.validatedBody in route handlers for type-safe access to validated request body

Files:

  • apps/medusa-be/src/api/store/reviews/middlewares.ts
  • apps/medusa-be/src/api/store/products/[id]/reviews/validators.ts
  • apps/medusa-be/src/api/admin-app-static.ts
  • apps/medusa-be/src/api/store/reviews/validators.ts
  • apps/medusa-be/src/api/admin/reviews/status/route.ts
  • apps/medusa-be/src/api/admin/reviews/route.ts
  • apps/medusa-be/src/api/admin/reviews/helpers.ts
  • apps/medusa-be/src/api/admin/reviews/validators.ts
  • apps/medusa-be/src/api/admin/reviews/middlewares.ts
  • apps/medusa-be/src/api/middlewares.ts
  • apps/medusa-be/src/api/admin/reviews/[id]/route.ts
  • apps/medusa-be/src/api/store/products/[id]/reviews/route.ts
  • apps/medusa-be/src/api/store/reviews/route.ts
  • apps/medusa-be/src/api/review-normalizers.ts
  • apps/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.ts
  • apps/medusa-be/src/api/store/products/[id]/reviews/validators.ts
  • apps/medusa-be/src/api/admin-app-static.ts
  • apps/medusa-be/src/api/store/reviews/validators.ts
  • apps/medusa-be/src/api/admin/reviews/status/route.ts
  • apps/medusa-be/src/api/admin/reviews/route.ts
  • apps/medusa-be/src/api/admin/reviews/helpers.ts
  • apps/medusa-be/src/api/admin/reviews/validators.ts
  • apps/medusa-be/src/api/admin/reviews/middlewares.ts
  • apps/medusa-be/src/api/middlewares.ts
  • apps/medusa-be/src/api/admin/reviews/[id]/route.ts
  • apps/medusa-be/src/api/store/products/[id]/reviews/route.ts
  • apps/medusa-be/src/api/store/reviews/route.ts
  • apps/medusa-be/src/api/review-normalizers.ts
  • apps/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.ts
  • apps/medusa-be/src/workflows/workflow-queue/steps/delete-workflow-queue-item.ts
  • apps/medusa-be/src/workflows/product-review/types.ts
  • apps/medusa-be/src/workflows/product-review/steps/mark-review-token-used.ts
  • apps/medusa-be/src/workflows/send-product-review-request.ts
  • apps/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
Use createStep() to define workflow steps with input validation and response wrapping
Use createWorkflow() to define multi-step business logic with rollback support
Return new StepResponse() from workflow steps to pass data to next steps
Return new WorkflowResponse() from workflows to pass final result to caller
Use transform() in workflows for data manipulation only; cannot contain side effects
Use when().then() for conditional logic in workflows instead of if statements
Do not reassign or iterate workflow variables; variable definitions are static at definition time
Use useQueryGraphStep() for Query operations within workflows
Use acquireLockStep(), releaseLockStep() for workflow-level locking instead of manual job locking

Files:

  • apps/medusa-be/src/workflows/product-review/steps/create-review.ts
  • apps/medusa-be/src/workflows/workflow-queue/steps/delete-workflow-queue-item.ts
  • apps/medusa-be/src/workflows/product-review/types.ts
  • apps/medusa-be/src/workflows/product-review/steps/mark-review-token-used.ts
  • apps/medusa-be/src/workflows/send-product-review-request.ts
  • apps/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.ts
  • apps/medusa-be/src/workflows/workflow-queue/steps/delete-workflow-queue-item.ts
  • apps/medusa-be/src/workflows/product-review/types.ts
  • apps/medusa-be/src/workflows/product-review/steps/mark-review-token-used.ts
  • apps/medusa-be/src/workflows/send-product-review-request.ts
  • apps/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; include where: { deleted_at: null } in DML format
Use model.float() for lower-precision numbers; use model.bigNumber() for high-precision values like money
Use provider identifier format {identifier}_{id} in DB provider_id field (e.g., my_shipping_default)

Files:

  • apps/medusa-be/src/modules/product-review/models/review-token.ts
  • apps/medusa-be/src/modules/product-review/models/review.ts
  • apps/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.ts alongside route definitions

Files:

  • apps/medusa-be/src/api/store/products/[id]/reviews/validators.ts
  • apps/medusa-be/src/api/store/reviews/validators.ts
  • apps/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: Extend MedusaService in module services for automatic CRUD methods
Call super(container, options) in module service constructors; do not use super(...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.ts
  • apps/medusa-be/src/modules/product-review/service.ts
  • apps/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: Use medusa exec ./path/to/script.ts [args] to run one-off scripts instead of creating HTTP endpoints
Use script pattern npx medusa exec ./src/scripts/startup.ts in startup hooks
Use destructive operations in medusa exec scripts, never in unprotected GET endpoints

Files:

  • apps/medusa-be/src/scripts/herbatica-seed-config.ts
  • apps/medusa-be/src/scripts/herbatica-reviews-seed.ts
  • apps/medusa-be/src/scripts/herbatica-xml-utils.ts
  • apps/medusa-be/src/scripts/herbatica-category-export.ts
  • apps/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 variables config in admin routes as it shadows export 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.ts
  • apps/medusa-be/src/api/admin/reviews/route.ts
  • apps/medusa-be/src/api/admin/reviews/helpers.ts
  • apps/medusa-be/src/api/admin/reviews/validators.ts
  • apps/medusa-be/src/api/admin/reviews/middlewares.ts
  • apps/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.ts evaluated 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: Use container.resolve() to access services in jobs and loaders
Lock overlapping background jobs to prevent concurrent conflicts
Use locking module's execute() 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 in src/jobs/__tests__/ as Medusa loads all src/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.tsx
  • apps/medusa-be/src/admin/lib/reviews.ts
  • apps/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}: Use import.meta.env.VITE_* for public env vars in React admin app; no secret env vars
Use import.meta.env.DEV and import.meta.env.PROD for environment detection in admin app

Files:

  • apps/medusa-be/src/admin/routes/reviews/[id]/page.tsx
  • apps/medusa-be/src/admin/lib/reviews.ts
  • apps/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.ts
  • apps/medusa-be/src/modules/workflow-queue/migrations/Migration20260610080000.ts
  • apps/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.tsx
  • apps/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.tsx
  • apps/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)

Comment thread apps/medusa-be/src/admin/lib/reviews.ts Outdated
Comment thread apps/medusa-be/src/api/admin-app-static.ts
Comment thread apps/medusa-be/src/api/admin/reviews/[id]/route.ts
Comment thread apps/medusa-be/src/api/admin/reviews/helpers.ts
Comment thread apps/medusa-be/src/api/admin/reviews/route.ts
Comment thread apps/medusa-be/src/utils/order-review-requests.ts Outdated
Comment thread apps/medusa-be/src/utils/order-review-requests.ts
Comment thread apps/medusa-be/src/utils/product-review-request-queue.ts Outdated
Comment thread apps/medusa-be/src/utils/workflow-queue-registry.ts
Comment thread apps/medusa-be/src/workflows/send-product-review-request.ts Outdated
@kilo-code-bot

kilo-code-bot Bot commented Jun 10, 2026

Copy link
Copy Markdown

Incremental review completed after 886bd73b9ea5c3a3ab7361c7a685a6ea2b992bc0.

Posting summary findings here instead of inline comments because the review environment blocked the new inline comment submission.

WARNING: apps/medusa-be/src/api/store/products/[id]/reviews/route.ts:49getReviewSummary() now still uses an unbounded second query.graph to fetch all approved reviews and compute average rating in-memory when count > 0, so the prior scalability and consistency risks remain after the migration from service.getReviewSummary to route-level Query.

WARNING: apps/medusa-be/src/modules/workflow-queue/migrations/Migration20260610100000.ts:6 — the backfill UPDATE workflow_queue_item SET order_id = ... is unbounded. Backfilling without batching can hold locks and bloat WAL/undo on populated tables.

SUGGESTION: apps/medusa-be/src/modules/workflow-queue/migrations/Migration20260610100000.ts:12 — the follow-up migration now creates an index name that Migration20260610080000 also defines on a fresh install path, so there may be redundant CREATE INDEX IF NOT EXISTS sequences across migrations; document ownership or exclude one source of truth.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

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 win

Reconsider the partial index on deleted_at.

The index IDX_review_token_deleted_at on column deleted_at with condition WHERE deleted_at IS NULL will only contain rows where deleted_at is NULL, making every indexed value NULL. This provides no selectivity benefit for queries.

For soft-delete patterns, you typically either:

  1. Rely on the WHERE deleted_at IS NULL condition in queries without a dedicated index on that column
  2. Add the WHERE deleted_at IS NULL condition 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_at itself, 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 win

Use 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

📥 Commits

Reviewing files that changed from the base of the PR and between e23dd38 and ea821dd.

📒 Files selected for processing (31)
  • .env.docker
  • apps/medusa-be/src/admin/lib/reviews.ts
  • apps/medusa-be/src/admin/routes/reviews/[id]/page.tsx
  • apps/medusa-be/src/api/admin-app-static.ts
  • apps/medusa-be/src/api/admin/reviews/[id]/route.ts
  • apps/medusa-be/src/api/admin/reviews/helpers.ts
  • apps/medusa-be/src/api/admin/reviews/route.ts
  • apps/medusa-be/src/api/admin/reviews/status/route.ts
  • apps/medusa-be/src/api/review-normalizers.ts
  • apps/medusa-be/src/api/store/products/[id]/reviews/route.ts
  • apps/medusa-be/src/api/store/reviews/helpers.ts
  • apps/medusa-be/src/jobs/workflow-queue-runner.ts
  • apps/medusa-be/src/modules/product-review/migrations/Migration20260610090000.ts
  • apps/medusa-be/src/modules/product-review/service.ts
  • apps/medusa-be/src/modules/resend/service.ts
  • apps/medusa-be/src/modules/workflow-queue/index.ts
  • apps/medusa-be/src/modules/workflow-queue/migrations/Migration20260610080000.ts
  • apps/medusa-be/src/modules/workflow-queue/service.ts
  • apps/medusa-be/src/scripts/herbatica-reviews-seed.ts
  • apps/medusa-be/src/scripts/herbatica-xml-utils.ts
  • apps/medusa-be/src/subscriber-helpers/product-review-request-on-payment/helper.ts
  • apps/medusa-be/src/utils/order-review-requests.ts
  • apps/medusa-be/src/utils/product-review-request-queue.ts
  • apps/medusa-be/src/utils/workflow-queue-registry.ts
  • apps/medusa-be/src/workflows/product-review/steps/update-review-status.ts
  • apps/medusa-be/src/workflows/product-review/steps/update-review.ts
  • apps/medusa-be/src/workflows/product-review/types.ts
  • apps/medusa-be/src/workflows/product-review/workflows/update-review-status.ts
  • apps/medusa-be/src/workflows/product-review/workflows/update-review.ts
  • apps/medusa-be/src/workflows/send-product-review-request.ts
  • docker-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.ts
  • apps/medusa-be/src/workflows/product-review/steps/update-review.ts
  • apps/medusa-be/src/workflows/product-review/steps/update-review-status.ts
  • apps/medusa-be/src/workflows/product-review/workflows/update-review.ts
  • apps/medusa-be/src/workflows/product-review/types.ts
  • apps/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}: Run npx tsc --noEmit for typechecking before committing
Always use braces around conditional blocks, even for single statements; Biome will expand them
Declare one variable per const/let statement, 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 as unknown when 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
Use Modules.* and ContainerRegistrationKeys.* 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 use as Type without prior validation

Files:

  • apps/medusa-be/src/workflows/product-review/workflows/update-review-status.ts
  • apps/medusa-be/src/workflows/product-review/steps/update-review.ts
  • apps/medusa-be/src/workflows/product-review/steps/update-review-status.ts
  • apps/medusa-be/src/modules/workflow-queue/index.ts
  • apps/medusa-be/src/api/admin/reviews/helpers.ts
  • apps/medusa-be/src/modules/workflow-queue/migrations/Migration20260610080000.ts
  • apps/medusa-be/src/workflows/product-review/workflows/update-review.ts
  • apps/medusa-be/src/workflows/product-review/types.ts
  • apps/medusa-be/src/utils/workflow-queue-registry.ts
  • apps/medusa-be/src/modules/product-review/service.ts
  • apps/medusa-be/src/api/admin/reviews/status/route.ts
  • apps/medusa-be/src/api/admin-app-static.ts
  • apps/medusa-be/src/admin/routes/reviews/[id]/page.tsx
  • apps/medusa-be/src/modules/product-review/migrations/Migration20260610090000.ts
  • apps/medusa-be/src/api/admin/reviews/[id]/route.ts
  • apps/medusa-be/src/api/admin/reviews/route.ts
  • apps/medusa-be/src/workflows/send-product-review-request.ts
  • apps/medusa-be/src/modules/workflow-queue/service.ts
  • apps/medusa-be/src/utils/product-review-request-queue.ts
  • apps/medusa-be/src/admin/lib/reviews.ts
  • apps/medusa-be/src/utils/order-review-requests.ts
  • apps/medusa-be/src/api/store/products/[id]/reviews/route.ts
  • apps/medusa-be/src/modules/resend/service.ts
  • apps/medusa-be/src/api/store/reviews/helpers.ts
  • apps/medusa-be/src/api/review-normalizers.ts
  • apps/medusa-be/src/scripts/herbatica-xml-utils.ts
  • apps/medusa-be/src/jobs/workflow-queue-runner.ts
  • apps/medusa-be/src/subscriber-helpers/product-review-request-on-payment/helper.ts
  • apps/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.ts
  • apps/medusa-be/src/workflows/product-review/steps/update-review.ts
  • apps/medusa-be/src/workflows/product-review/steps/update-review-status.ts
  • apps/medusa-be/src/modules/workflow-queue/index.ts
  • apps/medusa-be/src/api/admin/reviews/helpers.ts
  • apps/medusa-be/src/modules/workflow-queue/migrations/Migration20260610080000.ts
  • apps/medusa-be/src/workflows/product-review/workflows/update-review.ts
  • apps/medusa-be/src/workflows/product-review/types.ts
  • apps/medusa-be/src/utils/workflow-queue-registry.ts
  • apps/medusa-be/src/modules/product-review/service.ts
  • apps/medusa-be/src/api/admin/reviews/status/route.ts
  • apps/medusa-be/src/api/admin-app-static.ts
  • apps/medusa-be/src/admin/routes/reviews/[id]/page.tsx
  • apps/medusa-be/src/modules/product-review/migrations/Migration20260610090000.ts
  • apps/medusa-be/src/api/admin/reviews/[id]/route.ts
  • apps/medusa-be/src/api/admin/reviews/route.ts
  • apps/medusa-be/src/workflows/send-product-review-request.ts
  • apps/medusa-be/src/modules/workflow-queue/service.ts
  • apps/medusa-be/src/utils/product-review-request-queue.ts
  • apps/medusa-be/src/admin/lib/reviews.ts
  • apps/medusa-be/src/utils/order-review-requests.ts
  • apps/medusa-be/src/api/store/products/[id]/reviews/route.ts
  • apps/medusa-be/src/modules/resend/service.ts
  • apps/medusa-be/src/api/store/reviews/helpers.ts
  • apps/medusa-be/src/api/review-normalizers.ts
  • apps/medusa-be/src/scripts/herbatica-xml-utils.ts
  • apps/medusa-be/src/jobs/workflow-queue-runner.ts
  • apps/medusa-be/src/subscriber-helpers/product-review-request-on-payment/helper.ts
  • apps/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: Use const and explicit typing with dbService.sqlRaw<Type>() for SQL query results
Resolve logger using container.resolve<Logger>(ContainerRegistrationKeys.LOGGER)
Resolve Query using container.resolve<Query>(ContainerRegistrationKeys.QUERY)
Use Modules.LOCKING (not Modules.LOCK) to resolve locking services
Use Modules.CACHING (not Modules.CACHE) to resolve caching services
Throw MedusaError with appropriate type and message for error responses
Use MedusaError.Types.INVALID_DATA for 400 validation errors
Use MedusaError.Types.NOT_FOUND for 404 errors
Use MedusaError.Types.UNAUTHORIZED for 401 authentication errors
Use MedusaError.Types.NOT_ALLOWED for 400 permission errors
Use MedusaError.Types.DUPLICATE_ERROR for 422 duplicate entry errors
Use MedusaError.Types.CONFLICT for 409 conflict errors
Use caching module's computeKey() to generate stable cache keys from filters and pagination
Use caching module's get() with type assertion for cache retrieval
Use caching module's set() with TTL and tags for cache storage and bulk invalidation
Use caching module's clear() with tags to bulk-invalidate related cache entries
Always use Redis for caching in multi-container deployments instead of local variables
Batch operations using CHUNK_SIZE constant instead of unbounded loops

Files:

  • apps/medusa-be/src/workflows/product-review/workflows/update-review-status.ts
  • apps/medusa-be/src/workflows/product-review/steps/update-review.ts
  • apps/medusa-be/src/workflows/product-review/steps/update-review-status.ts
  • apps/medusa-be/src/modules/workflow-queue/index.ts
  • apps/medusa-be/src/api/admin/reviews/helpers.ts
  • apps/medusa-be/src/modules/workflow-queue/migrations/Migration20260610080000.ts
  • apps/medusa-be/src/workflows/product-review/workflows/update-review.ts
  • apps/medusa-be/src/workflows/product-review/types.ts
  • apps/medusa-be/src/utils/workflow-queue-registry.ts
  • apps/medusa-be/src/modules/product-review/service.ts
  • apps/medusa-be/src/api/admin/reviews/status/route.ts
  • apps/medusa-be/src/api/admin-app-static.ts
  • apps/medusa-be/src/modules/product-review/migrations/Migration20260610090000.ts
  • apps/medusa-be/src/api/admin/reviews/[id]/route.ts
  • apps/medusa-be/src/api/admin/reviews/route.ts
  • apps/medusa-be/src/workflows/send-product-review-request.ts
  • apps/medusa-be/src/modules/workflow-queue/service.ts
  • apps/medusa-be/src/utils/product-review-request-queue.ts
  • apps/medusa-be/src/admin/lib/reviews.ts
  • apps/medusa-be/src/utils/order-review-requests.ts
  • apps/medusa-be/src/api/store/products/[id]/reviews/route.ts
  • apps/medusa-be/src/modules/resend/service.ts
  • apps/medusa-be/src/api/store/reviews/helpers.ts
  • apps/medusa-be/src/api/review-normalizers.ts
  • apps/medusa-be/src/scripts/herbatica-xml-utils.ts
  • apps/medusa-be/src/jobs/workflow-queue-runner.ts
  • apps/medusa-be/src/subscriber-helpers/product-review-request-on-payment/helper.ts
  • apps/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
Use createStep() to define workflow steps with input validation and response wrapping
Use createWorkflow() to define multi-step business logic with rollback support
Return new StepResponse() from workflow steps to pass data to next steps
Return new WorkflowResponse() from workflows to pass final result to caller
Use transform() in workflows for data manipulation only; cannot contain side effects
Use when().then() for conditional logic in workflows instead of if statements
Do not reassign or iterate workflow variables; variable definitions are static at definition time
Use useQueryGraphStep() for Query operations within workflows
Use acquireLockStep(), releaseLockStep() for workflow-level locking instead of manual job locking

Files:

  • apps/medusa-be/src/workflows/product-review/workflows/update-review-status.ts
  • apps/medusa-be/src/workflows/product-review/steps/update-review.ts
  • apps/medusa-be/src/workflows/product-review/steps/update-review-status.ts
  • apps/medusa-be/src/workflows/product-review/workflows/update-review.ts
  • apps/medusa-be/src/workflows/product-review/types.ts
  • apps/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.ts
  • apps/medusa-be/src/workflows/product-review/steps/update-review.ts
  • apps/medusa-be/src/workflows/product-review/steps/update-review-status.ts
  • apps/medusa-be/src/workflows/product-review/workflows/update-review.ts
  • apps/medusa-be/src/workflows/product-review/types.ts
  • apps/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.ts
  • apps/medusa-be/src/modules/workflow-queue/migrations/Migration20260610080000.ts
  • apps/medusa-be/src/modules/product-review/service.ts
  • apps/medusa-be/src/modules/product-review/migrations/Migration20260610090000.ts
  • apps/medusa-be/src/modules/workflow-queue/service.ts
  • apps/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.ts
  • apps/medusa-be/src/modules/workflow-queue/migrations/Migration20260610080000.ts
  • apps/medusa-be/src/modules/product-review/service.ts
  • apps/medusa-be/src/modules/product-review/migrations/Migration20260610090000.ts
  • apps/medusa-be/src/modules/workflow-queue/service.ts
  • apps/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.ts
  • apps/medusa-be/src/modules/workflow-queue/migrations/Migration20260610080000.ts
  • apps/medusa-be/src/modules/product-review/service.ts
  • apps/medusa-be/src/modules/product-review/migrations/Migration20260610090000.ts
  • apps/medusa-be/src/modules/workflow-queue/service.ts
  • apps/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.ts
  • apps/medusa-be/src/api/admin/reviews/status/route.ts
  • apps/medusa-be/src/api/admin-app-static.ts
  • apps/medusa-be/src/api/admin/reviews/[id]/route.ts
  • apps/medusa-be/src/api/admin/reviews/route.ts
  • apps/medusa-be/src/api/store/products/[id]/reviews/route.ts
  • apps/medusa-be/src/api/store/reviews/helpers.ts
  • apps/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 variables config in admin routes as it shadows export const config = defineRouteConfig()
Admin routes are automatically protected and do not require explicit auth middleware

Files:

  • apps/medusa-be/src/api/admin/reviews/helpers.ts
  • apps/medusa-be/src/api/admin/reviews/status/route.ts
  • apps/medusa-be/src/api/admin/reviews/[id]/route.ts
  • apps/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: Use req.scope.resolve() to access container in routes
Colocate validators.ts and middlewares.ts with each route file in the same directory
Use validateAndTransformBody(Schema) middleware for POST/PUT request validation
Use validateAndTransformQuery(Schema) middleware for GET request query parameter validation
Use req.validatedBody in route handlers for type-safe access to validated request body

Files:

  • apps/medusa-be/src/api/admin/reviews/helpers.ts
  • apps/medusa-be/src/api/admin/reviews/status/route.ts
  • apps/medusa-be/src/api/admin-app-static.ts
  • apps/medusa-be/src/api/admin/reviews/[id]/route.ts
  • apps/medusa-be/src/api/admin/reviews/route.ts
  • apps/medusa-be/src/api/store/products/[id]/reviews/route.ts
  • apps/medusa-be/src/api/store/reviews/helpers.ts
  • apps/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.ts
  • apps/medusa-be/src/api/admin/reviews/status/route.ts
  • apps/medusa-be/src/api/admin-app-static.ts
  • apps/medusa-be/src/api/admin/reviews/[id]/route.ts
  • apps/medusa-be/src/api/admin/reviews/route.ts
  • apps/medusa-be/src/api/store/products/[id]/reviews/route.ts
  • apps/medusa-be/src/api/store/reviews/helpers.ts
  • apps/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: Extend MedusaService in module services for automatic CRUD methods
Call super(container, options) in module service constructors; do not use super(...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.ts
  • apps/medusa-be/src/modules/workflow-queue/service.ts
  • apps/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.tsx
  • apps/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}: Use import.meta.env.VITE_* for public env vars in React admin app; no secret env vars
Use import.meta.env.DEV and import.meta.env.PROD for environment detection in admin app

Files:

  • apps/medusa-be/src/admin/routes/reviews/[id]/page.tsx
  • apps/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: Use medusa exec ./path/to/script.ts [args] to run one-off scripts instead of creating HTTP endpoints
Use script pattern npx medusa exec ./src/scripts/startup.ts in startup hooks
Use destructive operations in medusa exec scripts, never in unprotected GET endpoints

Files:

  • apps/medusa-be/src/scripts/herbatica-xml-utils.ts
  • apps/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: Use container.resolve() to access services in jobs and loaders
Lock overlapping background jobs to prevent concurrent conflicts
Use locking module's execute() 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 in src/jobs/__tests__/ as Medusa loads all src/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.ts
  • apps/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 $1 for workflow and $2 for orderId (keeping the parameters array order aligned).
  • Check how manager.execute formats placeholders in this codebase (search for other manager.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

Comment thread apps/medusa-be/src/modules/workflow-queue/service.ts Outdated
@KaiUweCZE
KaiUweCZE merged commit 9e3a4ed into master Jun 10, 2026
7 checks passed
This was referenced Jun 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants