{"owner":"evershopcommerce","repo":"evershop","hasSkills":true,"totalSkillsCount":5,"totalTokensCount":5763,"categories":["claude-rule","plugin-manifest"],"hasMcp":false,"mcpConfig":null,"found":["CLAUDE.md","packages/create-evershop-app/README.md","packages/create-evershop-app/sample/extensions/sample/Readme.md","packages/evershop/README.md","packages/postgres-query-builder/README.md"],"skills":{"CLAUDE.md":"# EverShop Core — Project Instructions for Claude\n\nThis is the **EverShop core repository** — the codebase for the modular monolith eCommerce platform built on Express + React (SSR) + PostgreSQL + GraphQL. The package source lives at `packages/evershop/src/` and is published as `@evershop/evershop`.\n\nThe author and maintainer is The Nguyen (`support@evershop.io`). Assume deep familiarity with the codebase.\n\n## Read the wiki first\n\nA curated wiki for this codebase lives in `wiki/`. **Before answering architectural questions or making non-trivial changes, read the relevant wiki page(s)**, not just the docs in `../docs/` or the source code. The wiki is hand-curated to be the fastest source of truth for \"how does this actually work\" questions.\n\n- `wiki/index.md` — catalog of all pages with one-line summaries. Read this first to find the right page.\n- `wiki/log.md` — chronological record of ingests, queries, and audits.\n- `wiki/<topic>.md` — the content pages.\n\nIf a page doesn't exist for the topic you need, that's a signal to **ingest** (see Operations below).\n\n## Operations\n\n### Query\n\nWhen the user asks a question that the wiki could answer:\n\n1. Open `wiki/index.md` and find candidate pages.\n2. Read those pages.\n3. Answer using the wiki content. Cite pages by filename (e.g., \"see `wiki/widgets.md`\") so the user can jump in.\n4. If the wiki content is **outdated relative to the code** (rename, removal, signature change), update the wiki page in the same response and append a note to `wiki/log.md`.\n\n### Ingest\n\nWhen the user explains something non-obvious about the codebase, or when you investigate an unfamiliar subsystem and the answer is worth keeping:\n\n1. Discuss the takeaways with the user inline (don't go silent for minutes writing files).\n2. Decide whether the knowledge belongs on an existing page or warrants a new one. Prefer updating existing pages — a page with five short sections beats five tiny pages.\n3. Write/update the page using the conventions below.\n4. Update `wiki/index.md` if a new page was added or a description changed.\n5. Append a one-line entry to `wiki/log.md` with prefix `## [YYYY-MM-DD] ingest | <topic>`.\n\n### Lint\n\nWhen asked to audit the wiki, or when you notice drift while answering questions:\n\n- Verify file paths and line references still resolve (they decay as files move).\n- Check that named functions/flags/files referenced in the wiki still exist (`grep`, `Read`).\n- Reconcile contradictions between pages.\n- Flag pages that haven't been touched in a long time *and* describe an area that has clearly evolved (use `git log --oneline -- <path>` to spot churn).\n- Append a `## [YYYY-MM-DD] lint | <scope>` entry to `wiki/log.md` summarizing what was checked and what changed.\n\n## Page conventions\n\nEvery page follows this shape:\n\n```md\n# <Title>\n\n**TL;DR.** One paragraph. The thing the user came here to learn, said directly.\n\n## <Section>\n\nBody. Code snippets go in fenced blocks with the language tag. File references use `relative/path:line` format so the user can click into them.\n\n## See also\n- [Other page](other-page.md) — one-line hook\n```\n\nSpecifics:\n\n- **File paths.** Always relative to the package root (`packages/evershop/src/...`) unless the file lives outside that tree. Add `:line` suffix when pointing at a specific implementation.\n- **Code samples.** Prefer real, compilable snippets pulled from the codebase over invented examples. If you must invent, mark it clearly.\n- **No marketing.** No \"powerful\", \"robust\", \"comprehensive\". Just what it is and how it works.\n- **Be willing to contradict the public docs.** If `../docs/` is wrong, the wiki should say so and explain the actual current behavior.\n- **Date format.** ISO `YYYY-MM-DD` everywhere.\n\n## EverShop quick reference\n\nFor deep understanding, read the wiki pages. This section is the cheat sheet.\n\n### Stack\n- **Runtime:** Node.js ≥ 20, Express, React 18 with SSR + hydration\n- **Database:** PostgreSQL 13+ (no other DBs supported; SQL is plain Postgres)\n- **GraphQL:** schema assembled at startup from per-module `.graphql` files\n- **Bundler:** webpack 5 with SWC for transforms (no Babel)\n- **Forms:** react-hook-form (wrapped by `components/common/form/Form.tsx`)\n- **Styling:** Tailwind v4 + PostCSS + custom plugins\n\n### Application type\nMulti-page application (MPA) — each route gets its own bundle and a full HTML response. Hydrated on the client. Not a SPA — there is no client-side router.\n\n### File / folder conventions\n- **Migrations:** `Version-X.Y.Z.ts` (hyphen, not underscore) in `<module>/migration/`\n- **Routes:** folder name = route ID, alphabetic only (a-z, A-Z), `route.json` declares the route\n- **Middleware:** lowercase first letter, bracket-syntax ordering `[after]name[before].ts`\n- **Master components:** uppercase first letter, `.tsx`, optional `export const layout = { areaId, sortOrder }`\n- **Shared between routes:** folder named `routeA+routeB/` (e.g. `productEdit+productNew/`)\n- **Site-wide middleware:** `pages/admin/all/`, `pages/frontStore/all/`, `pages/global/`, `api/global/`\n- **Subscribers:** `subscribers/<event_name>/<handler>.ts`\n- **Modules:** core in `packages/evershop/src/modules/`, user extensions in `extensions/` (project root)\n- **Module ID:** must be unique across the system\n\n### Bootstrap is a hard wall\nThe hook system and registry are **locked** after every module's `bootstrap.ts` runs. Calling `addProcessor`, `hookBefore`, `hookAfter`, `registerWidget`, `registerJob`, `registerEmailService`, `registerPaymentMethod`, etc. from inside a middleware or request handler **throws**. Always register from `bootstrap.ts`.\n\n### Public import paths\nSee `wiki/reference.md` for the full table. The most common ones:\n\n```ts\nimport { select, insert, update, del, insertOnUpdate } from '@evershop/evershop/lib/postgres/query';\nimport { pool, getConnection } from '@evershop/evershop/lib/postgres';\nimport { addProcessor, getValue } from '@evershop/evershop/lib/util/registry';\nimport { hookBefore, hookAfter, hookable } from '@evershop/evershop/lib/util/hookable';\nimport { emit } from '@evershop/evershop/lib/event';\nimport { createSubscriber } from '@evershop/evershop/lib/event/subscriber';\nimport { buildUrl, buildAbsoluteUrl } from '@evershop/evershop/lib/router';\nimport { registerWidget } from '@evershop/evershop/lib/widget';\nimport { setContextValue, getContextValue } from '@evershop/evershop/graphql/services';\n```\n\n### Common pitfalls\n- `import { Request, Response } from 'express'` — wrong. Use `EvershopRequest`/`EvershopResponse` from `@evershop/evershop/types/request` and `types/response`.\n- `module.exports` — wrong. ESM. Use `export default`.\n- MySQL syntax — wrong. PostgreSQL. Use `IDENTITY` or `SERIAL`, double-quoted identifiers, `JSONB`, `gen_random_uuid()`.\n- `migrations/` (plural) folder — wrong. Singular `migration/`.\n- `Version_1.0.0.ts` (underscore) — wrong. Hyphen: `Version-1.0.0.ts`.\n- `pages/frontend/` — wrong. `pages/frontStore/`.\n- Arrow functions in hookable / processor callbacks when context is needed — `this` is bound via `.call()`, arrow functions can't access it.\n- Adding a hook or processor from a middleware — locked after bootstrap, throws.\n\n### Common mistakes\n\nThe pitfalls above are syntactic — caught by lint or first compile. The ones below are runtime or integration traps. They compile cleanly and fail later. Each has bitten the codebase; the wiki pages explain *why* and show the fix.\n\n- **API handler that sends a response with a 2-arg `(request, response)` signature → `ERR_HTTP_HEADERS_SENT`.** The framework inspects `function.length`; a 2-arg handler is treated as passive, so it auto-calls `next()` after your function resolves and `apiResponse` tries to send headers again. If you call `response.json()` / `response.send()` / `response.redirect()`, declare the third `next` parameter even if you never call it — the 3-arg signature disables auto-next. See [wiki/middleware-system.md → Active vs passive middleware](wiki/middleware-system.md#active-vs-passive-middleware-2-arg-vs-3-arg).\n- **Chaining `.where()` or `.orderBy()` directly off `.on()` in a query-builder JOIN → `where is not a function` at runtime.** `.on()` returns a `Node`; `.where()` and `.orderBy()` live on `Query`/`SelectQuery`, not `Node`. Hold the query handle in a variable and call `.where()` / `.orderBy()` on it separately. The `.where().and().execute()` chain works fine (Node has `.and()` and `.execute()`) — the trap is only joins. See [wiki/database.md → What chains on what](wiki/database.md#what-chains-on-what-the-gotcha).\n- **Passing `(column, alias)` to the top-level `select(...)` → silent column rename → `column \"X\" does not exist` at runtime.** The top-level `select(...)` is *variadic over columns* — `select('foo.uuid', 'method_uuid')` treats both strings as columns, not as `(column, alias)`. Only the chained `.select(col, alias)` form supports aliasing. Use `select().from(table).select(col, alias)` instead. See [wiki/database.md → `select(...)` is variadic](wiki/database.md#select-is-variadic--it-does-not-take-column-alias).\n- **Passing `{ isSQL: true, value: '...' }` to `.given()` for raw SQL in UPDATE/INSERT → `invalid input syntax for type ...` at runtime.** `UpdateQuery.given` / `InsertQuery.given` call `toString(value)` on every entry, which JSON-stringifies object values. The `{isSQL, value}` raw-escape convention is **only** honored inside `.where()` / `Leaf` / `RawLeaf`, not for SET / VALUES. When you need raw SQL on the write side (`COALESCE(col, NOW())`, `col + 1`, `gen_random_uuid()`), drop to `connection.query()` with bind parameters for just the user values. Canonical pattern: `oms/services/updateShipmentStatus.ts:79-100`.\n- **`.execute(connection)` / `.load(connection)` on a fresh `getConnection()` PoolClient before `startTransaction(connection)` → `Release called on client which has already been released to the pool` at runtime.** The query-builder's internal `release()` only short-circuits when `connection.INTRANSACTION === true`, a flag exclusively set by `startTransaction`. Pre-tx reads on a freshly-acquired PoolClient auto-release it back to the pool, and the next `startTransaction(connection)` operates on a detached client. Rule: either call `startTransaction` IMMEDIATELY after `getConnection`, or run pre-tx reads on the shared `pool` (which `release()` ignores) and acquire the dedicated PoolClient only at the top of the tx. The canonical \"delayed tx\" pattern (necessary when an external network call has to run between read and write — e.g. `carrier.createLabel()`) is in `oms/services/createShipment.ts:330-410`.\n- **Hook called after a conditional early return in a React component → `Rendered more hooks than during the previous render`.** All hooks must run in the same order on every render. If one render takes an early return before a `useEffect` and the next render reaches it, React errors. Move every hook above any conditional return.\n- **`.admin.graphql` type referenced from a non-admin `.graphql` file → \"Unknown type X\" at storefront schema build.** `buildStoreFrontSchema` filters out `.admin.graphql`; types defined there aren't visible to the storefront schema. Either move the type to a non-admin file or mark the referencing file `.admin.graphql` too. The two schemas build separately — admin sees both, storefront sees only non-admin.\n- **Dropping a DB column without grepping across modules.** EverShop modules share tables. A resolver in `modules/base/` may read a column owned by `modules/checkout/`. When dropping a column, `grep -rn \"table\\\\.column\" packages/evershop/src` across the whole tree, not just the owning module.\n- **New `.js` files in new code paths.** The codebase has mixed `.js` and `.ts` because the migration to TypeScript is incremental, but **new authorship is `.ts`** (or `.tsx` for React). Editing an existing `.js` keeps it `.js` for small changes; full rewrites are a good moment to switch. See [wiki/module-structure.md → TypeScript by default](wiki/module-structure.md#typescript-by-default).\n- **`hookable()` keys hooks by the wrapped function's `.name`, so a `…Impl` declaration silently kills its public hooks.** `hookable(fooImpl)` registers under `'fooImpl'`, but a `hookBeforeFoo` helper that calls `hookBefore('foo', …)` registers under `'foo'` — they never meet, the hook never fires, and nothing errors (the wrapped function still runs, the transaction still commits). Wrap a **named function expression** whose intrinsic name *is* the hook key, even if the binding differs: `const fooImpl = async function foo() {…}` (the `checkout.ts:10` idiom — `const _checkout = async function checkout(`). A plain `function fooImpl() {}` declaration sets `.name = 'fooImpl'` and breaks it. See [wiki/hooks.md → Common pitfalls](wiki/hooks.md#common-pitfalls); guard test `modules/oms/tests/unit/hookNameAlignment.test.js`.\n- **A widget `settingComponent` that reads a list setting as `watch('settings.x') ?? initial` works in the page-builder drawer but throws `items.map is not a function` on the legacy `/admin/widgets/edit` page.** The two surfaces seed settings differently: the drawer's page-level form holds real arrays/objects, but the legacy `<Form>` seeds list fields as a JSON **string** via a hidden `defaultValue={JSON.stringify(...)}` input — and `??` only guards null, so the string reaches `RepeatableAccordion` and would also fail the widget's AJV array schema on save (settings are never parsed in the save path). Read list settings with `useArraySetting('settings.x', initial)` and mutate via `asArray(getValues('settings.x'), initial)` (both from `@components/common/page-builder`), or hold the array with `useFieldArray` like `SlideshowSetting`. See [wiki/page-builder.md → Widget settings run on two surfaces](wiki/page-builder.md#widget-settings-run-on-two-surfaces-list-field-trap).\n\n## Doing work in this repo\n\n- The published package is built from `src/` to `dist/` via SWC (`npm run compile`). Runtime loads `.js` from `dist/`. When editing, edit `.ts` in `src/`.\n- Tests run with Jest: `npm test` from the repo root.\n- Lint with `npm run lint`.\n- Dev server: `npm run dev` (uses `webpack-dev-middleware` + HMR).\n- Build for production: `npm run build` then `npm run start`.\n- Never bypass `husky` hooks (`--no-verify`) or skip type/lint failures without an explicit go-ahead.\n","packages/create-evershop-app/README.md":"# create-evershop-app\n\nThis package includes the global command for [Create EverShop App](https://evershop.io/).<br> Please refer to its documentation:\n\n- [Getting Started](https://evershop.io/docs/development/getting-started/introduction) – How to create a new app.\n- [Development Guide](https://evershop.io/docs/development/) – How to develop an ecommerce web app with EverShop.\n","packages/create-evershop-app/sample/extensions/sample/Readme.md":"# Sample Extension\n\nThis is a sample extension for Evershop. It demonstrates how to build a simple extension for your Evershop store.\n\n## Enable/Disable the extension\n\nTo enable the extension, modify the configuration file `config/default.json` and set the `enabled` property to `true`:\n\n```json\n{\n  \"system\": {\n    \"extensions\": [\n      {\n        \"name\": \"sample\",\n        \"resolve\": \"extensions/sample\",\n        \"enabled\": true\n      }\n    ]\n  }\n}\n```\n\n> **Warning**\n> Enable/disable the extension requires running the command `npm run build` again.\n","packages/evershop/README.md":"<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</p>\n<p align=\"center\">\n<img width=\"60\" height=\"68\" alt=\"EverShop Logo\" src=\"https://raw.githubusercontent.com/evershopcommerce/evershop/dev/.github/images/logo-green.png\"/>\n</p>\n<p align=\"center\">\n  <h1 align=\"center\">EverShop</h1>\n</p>\n<h4 align=\"center\">\n    <a href=\"https://evershop.io/docs/development/getting-started/introduction\">Documentation</a> |\n    <a href=\"https://demo.evershop.io/\">Demo</a>\n</h4>\n\n<p align=\"center\">\n  <img src=\"https://github.com/evershopcommerce/evershop/actions/workflows/build_test.yml/badge.svg\" alt=\"Github Action\">\n  <a href=\"https://twitter.com/evershopjs\">\n    <img alt=\"Twitter Follow\" src=\"https://img.shields.io/twitter/follow/evershopjs?style=social\">\n  </a>\n  <a href=\"https://discord.gg/GSzt7dt7RM\">\n    <img src=\"https://img.shields.io/discord/757179260417867879?label=discord\" alt=\"Discord\">\n  </a>\n  <a href=\"https://opensource.org/licenses/GPL-3.0\">\n    <img src=\"https://img.shields.io/badge/License-GPLv3-blue.svg\" alt=\"License\">\n  </a>\n</p>\n\n<p align=\"center\">\n<img alt=\"EverShop\" width=\"950\" src=\"https://raw.githubusercontent.com/evershopcommerce/evershop/dev/.github/images/banner.png\"/>\n</p>\n\n## Introduction\n\nEverShop is a modern, TypeScript-first eCommerce platform built with GraphQL and React. Designed for developers, it offers essential commerce features in a modular, fully customizable architecture—perfect for building tailored shopping experiences with confidence and speed.\n\n## Installation Using Docker\n\nYou can get started with EverShop in minutes by using the Docker image. The Docker image is a great way to get started with EverShop without having to worry about installing dependencies or configuring your environment.\n\n```bash\ncurl -sSL https://raw.githubusercontent.com/evershopcommerce/evershop/main/docker-compose.yml > docker-compose.yml\ndocker-compose up -d\n```\n\nFor the full installation guide, please refer to our [Installation guide](https://evershop.io/docs/development/getting-started/installation-guide).\n\n## Documentation\n\n- [Installation guide](https://evershop.io/docs/development/getting-started/installation-guide).\n\n- [Extension development](https://evershop.io/docs/development/module/create-your-first-extension).\n\n- [Theme development](https://evershop.io/docs/development/theme/theme-overview).\n\n## Demo\n\nExplore our demo store.\n\n<p align=\"left\">\n  <a href=\"https://demo.evershop.io/admin\" target=\"_blank\">\n    <img alt=\"evershop-backend-demo\" height=\"35\" alt=\"EverShop Admin Demo\" src=\"https://raw.githubusercontent.com/evershopcommerce/evershop/dev/.github/images/evershop-demo-back.png\"/>\n  </a>\n  <a href=\"https://demo.evershop.io/\" target=\"_blank\">\n    <img alt=\"evershop-store-demo\" height=\"35\" alt=\"EverShop Store Demo\" src=\"https://raw.githubusercontent.com/evershopcommerce/evershop/dev/.github/images/evershop-demo-front.png\"/>\n  </a>\n</p>\n<b>Demo user:</b>\n\nEmail: demo@evershop.io<br/>\nPassword: 123456\n\n## Support\n\nIf you like my work, feel free to:\n\n- ⭐ this repository. It helps.\n- [![Tweet](https://img.shields.io/twitter/url/http/shields.io.svg?style=social)][tweet] about EverShop. Thank you!\n\n[tweet]: https://twitter.com/intent/tweet?url=https%3A%2F%2Fgithub.com%2Fevershopcommerce%2Fevershop&text=Awesome%20React%20Ecommerce%20Project&hashtags=react,ecommerce,expressjs,graphql\n\n## Contributing\n\nEverShop is an open-source project. We are committed to a fully transparent development process and appreciate highly any contributions. Whether you are helping us fix bugs, proposing new features, improving our documentation or spreading the word - we would love to have you as part of the EverShop community.\n\n### Ask a question about EverShop\n\nYou can ask questions, and participate in discussions about EverShop-related topics in the EverShop Discord channel.\n\n<a href=\"https://discord.gg/GSzt7dt7RM\"><img src=\"https://raw.githubusercontent.com/evershopcommerce/evershop/dev/.github/images/discord_banner_github.svg\" /></a>\n\n### Create a bug report\n\nIf you see an error message or run into an issue, please [create bug report](https://github.com/evershopcommerce/evershop/issues/new). This effort is valued and it will help all EverShop users.\n\n### Submit a feature request\n\nIf you have an idea, or you're missing a capability that would make development easier and more robust, please [Submit feature request](https://github.com/evershopcommerce/evershop/issues/new).\n\nIf a similar feature request already exists, don't forget to leave a \"+1\".\nIf you add some more information such as your thoughts and vision about the feature, your comments will be embraced warmly :)\n\nPlease refer to our [Contribution Guidelines](./CONTRIBUTING.md) and [Code of Conduct](./CODE_OF_CONDUCT.md).\n\n## License\n\n[GPL-3.0 License](https://github.com/evershopcommerce/evershop/blob/main/LICENSE)\n","packages/postgres-query-builder/README.md":"# PostgreSQL query builder for Node\n\nA PostgreSQL query builder for NodeJS.\n\n## Installation\n\n```javascript\nnpm install @evershop/postgres-query-builder\n```\n\n## Usage guide\n\nIt implements async/await.\n\n### Simple select\n\n```javascript\nconst { select } = require('@evershop/postgres-query-builder');\n\nconst products = await select('*')\n  .from('product')\n  .where('product_id', '>', 1)\n  .execute(pool);\n```\n\n### More complex where\n\n```javascript\nconst { select } = require('@evershop/postgres-query-builder');\n\nconst products = await select('*')\n  .from('product')\n  .where('product_id', '>', 1)\n  .and('sku', 'LIKE', 'sku')\n  .execute(pool);\n```\n\n### Event more complex where\n\n```javascript\nconst { select } = require('@evershop/postgres-query-builder');\n\nconst query = select('*').from('product');\nquery.where('product_id', '>', 1).and('sku', 'LIKE', 'sku');\nquery.orWhere('price', '>', 100);\n\nconst products = await query.execute(pool);\n```\n\n### Join table\n\n```javascript\nconst { select } = require('@evershop/postgres-query-builder');\n\nconst query = select('*').from('product');\nquery.leftJoin('price').on('product.`product_id`', '=', 'price.`product_id`');\nquery.where('product_id', '>', 1).and('sku', 'LIKE', 'sku');\nquery.andWhere('price', '>', 100);\n\nconst products = await query.execute(pool);\n```\n\n### Insert&update\n\n<table>\n<tr>\n<th> user_id </th>\n<th> name </th>\n<th> email </th>\n<th> phone </th>\n<th> status </th>\n</tr>\n<tr>\n<td>\n  1\n</td>\n<td>\n  David\n</td>\n<td>\n  emai@email.com\n</td>\n<td>\n  123456\n</td>\n<td>\n  1\n</td>\n</tr>\n</table>\n\n````javascript\n```javascript\nconst {insert} = require('@evershop/postgres-query-builder')\n\nconst query = insert(\"user\")\n.given({name: \"David\", email: \"email@email.com\", \"phone\": \"123456\", status: 1, notExistedColumn: \"This will not be a part of the query\"});\nawait query.execute(pool);\n````\n\n```javascript\nconst { update } = require('@evershop/postgres-query-builder');\n\nconst query = update('user')\n  .given({\n    name: 'David',\n    email: 'email@email.com',\n    phone: '123456',\n    status: 1,\n    notExistedColumn: 'This will not be a part of query'\n  })\n  .where('user_id', '=', 1);\nawait query.execute(pool);\n```\n\n### Working with transaction\n\n```javascript\nconst { Pool } = require('pg');\nconst {\n  insert,\n  getConnection,\n  startTransaction,\n  commit,\n  rollback\n} = require('@evershop/postgres-query-builder');\n\nconst pool = new Pool(connectionSetting);\n\n// Create a connection from the pool\nconst connection = await getConnection(pool);\n\n// Start a transaction\nawait startTransaction(connection);\ntry {\n  await insert('user')\n    .given({\n      name: 'David',\n      email: 'email@email.com',\n      phone: '123456',\n      status: 1,\n      notExistedColumn: 'This will not be a part of the query'\n    })\n    .execute(connection);\n  await commit(connection);\n} catch (e) {\n  await rollback(connection);\n}\n```\n\n## Security\n\nAll user provided data will be escaped.\n"},"files":{"CLAUDE.md":"# EverShop Core — Project Instructions for Claude\n\nThis is the **EverShop core repository** — the codebase for the modular monolith eCommerce platform built on Express + React (SSR) + PostgreSQL + GraphQL. The package source lives at `packages/evershop/src/` and is published as `@evershop/evershop`.\n\nThe author and maintainer is The Nguyen (`support@evershop.io`). Assume deep familiarity with the codebase.\n\n## Read the wiki first\n\nA curated wiki for this codebase lives in `wiki/`. **Before answering architectural questions or making non-trivial changes, read the relevant wiki page(s)**, not just the docs in `../docs/` or the source code. The wiki is hand-curated to be the fastest source of truth for \"how does this actually work\" questions.\n\n- `wiki/index.md` — catalog of all pages with one-line summaries. Read this first to find the right page.\n- `wiki/log.md` — chronological record of ingests, queries, and audits.\n- `wiki/<topic>.md` — the content pages.\n\nIf a page doesn't exist for the topic you need, that's a signal to **ingest** (see Operations below).\n\n## Operations\n\n### Query\n\nWhen the user asks a question that the wiki could answer:\n\n1. Open `wiki/index.md` and find candidate pages.\n2. Read those pages.\n3. Answer using the wiki content. Cite pages by filename (e.g., \"see `wiki/widgets.md`\") so the user can jump in.\n4. If the wiki content is **outdated relative to the code** (rename, removal, signature change), update the wiki page in the same response and append a note to `wiki/log.md`.\n\n### Ingest\n\nWhen the user explains something non-obvious about the codebase, or when you investigate an unfamiliar subsystem and the answer is worth keeping:\n\n1. Discuss the takeaways with the user inline (don't go silent for minutes writing files).\n2. Decide whether the knowledge belongs on an existing page or warrants a new one. Prefer updating existing pages — a page with five short sections beats five tiny pages.\n3. Write/update the page using the conventions below.\n4. Update `wiki/index.md` if a new page was added or a description changed.\n5. Append a one-line entry to `wiki/log.md` with prefix `## [YYYY-MM-DD] ingest | <topic>`.\n\n### Lint\n\nWhen asked to audit the wiki, or when you notice drift while answering questions:\n\n- Verify file paths and line references still resolve (they decay as files move).\n- Check that named functions/flags/files referenced in the wiki still exist (`grep`, `Read`).\n- Reconcile contradictions between pages.\n- Flag pages that haven't been touched in a long time *and* describe an area that has clearly evolved (use `git log --oneline -- <path>` to spot churn).\n- Append a `## [YYYY-MM-DD] lint | <scope>` entry to `wiki/log.md` summarizing what was checked and what changed.\n\n## Page conventions\n\nEvery page follows this shape:\n\n```md\n# <Title>\n\n**TL;DR.** One paragraph. The thing the user came here to learn, said directly.\n\n## <Section>\n\nBody. Code snippets go in fenced blocks with the language tag. File references use `relative/path:line` format so the user can click into them.\n\n## See also\n- [Other page](other-page.md) — one-line hook\n```\n\nSpecifics:\n\n- **File paths.** Always relative to the package root (`packages/evershop/src/...`) unless the file lives outside that tree. Add `:line` suffix when pointing at a specific implementation.\n- **Code samples.** Prefer real, compilable snippets pulled from the codebase over invented examples. If you must invent, mark it clearly.\n- **No marketing.** No \"powerful\", \"robust\", \"comprehensive\". Just what it is and how it works.\n- **Be willing to contradict the public docs.** If `../docs/` is wrong, the wiki should say so and explain the actual current behavior.\n- **Date format.** ISO `YYYY-MM-DD` everywhere.\n\n## EverShop quick reference\n\nFor deep understanding, read the wiki pages. This section is the cheat sheet.\n\n### Stack\n- **Runtime:** Node.js ≥ 20, Express, React 18 with SSR + hydration\n- **Database:** PostgreSQL 13+ (no other DBs supported; SQL is plain Postgres)\n- **GraphQL:** schema assembled at startup from per-module `.graphql` files\n- **Bundler:** webpack 5 with SWC for transforms (no Babel)\n- **Forms:** react-hook-form (wrapped by `components/common/form/Form.tsx`)\n- **Styling:** Tailwind v4 + PostCSS + custom plugins\n\n### Application type\nMulti-page application (MPA) — each route gets its own bundle and a full HTML response. Hydrated on the client. Not a SPA — there is no client-side router.\n\n### File / folder conventions\n- **Migrations:** `Version-X.Y.Z.ts` (hyphen, not underscore) in `<module>/migration/`\n- **Routes:** folder name = route ID, alphabetic only (a-z, A-Z), `route.json` declares the route\n- **Middleware:** lowercase first letter, bracket-syntax ordering `[after]name[before].ts`\n- **Master components:** uppercase first letter, `.tsx`, optional `export const layout = { areaId, sortOrder }`\n- **Shared between routes:** folder named `routeA+routeB/` (e.g. `productEdit+productNew/`)\n- **Site-wide middleware:** `pages/admin/all/`, `pages/frontStore/all/`, `pages/global/`, `api/global/`\n- **Subscribers:** `subscribers/<event_name>/<handler>.ts`\n- **Modules:** core in `packages/evershop/src/modules/`, user extensions in `extensions/` (project root)\n- **Module ID:** must be unique across the system\n\n### Bootstrap is a hard wall\nThe hook system and registry are **locked** after every module's `bootstrap.ts` runs. Calling `addProcessor`, `hookBefore`, `hookAfter`, `registerWidget`, `registerJob`, `registerEmailService`, `registerPaymentMethod`, etc. from inside a middleware or request handler **throws**. Always register from `bootstrap.ts`.\n\n### Public import paths\nSee `wiki/reference.md` for the full table. The most common ones:\n\n```ts\nimport { select, insert, update, del, insertOnUpdate } from '@evershop/evershop/lib/postgres/query';\nimport { pool, getConnection } from '@evershop/evershop/lib/postgres';\nimport { addProcessor, getValue } from '@evershop/evershop/lib/util/registry';\nimport { hookBefore, hookAfter, hookable } from '@evershop/evershop/lib/util/hookable';\nimport { emit } from '@evershop/evershop/lib/event';\nimport { createSubscriber } from '@evershop/evershop/lib/event/subscriber';\nimport { buildUrl, buildAbsoluteUrl } from '@evershop/evershop/lib/router';\nimport { registerWidget } from '@evershop/evershop/lib/widget';\nimport { setContextValue, getContextValue } from '@evershop/evershop/graphql/services';\n```\n\n### Common pitfalls\n- `import { Request, Response } from 'express'` — wrong. Use `EvershopRequest`/`EvershopResponse` from `@evershop/evershop/types/request` and `types/response`.\n- `module.exports` — wrong. ESM. Use `export default`.\n- MySQL syntax — wrong. PostgreSQL. Use `IDENTITY` or `SERIAL`, double-quoted identifiers, `JSONB`, `gen_random_uuid()`.\n- `migrations/` (plural) folder — wrong. Singular `migration/`.\n- `Version_1.0.0.ts` (underscore) — wrong. Hyphen: `Version-1.0.0.ts`.\n- `pages/frontend/` — wrong. `pages/frontStore/`.\n- Arrow functions in hookable / processor callbacks when context is needed — `this` is bound via `.call()`, arrow functions can't access it.\n- Adding a hook or processor from a middleware — locked after bootstrap, throws.\n\n### Common mistakes\n\nThe pitfalls above are syntactic — caught by lint or first compile. The ones below are runtime or integration traps. They compile cleanly and fail later. Each has bitten the codebase; the wiki pages explain *why* and show the fix.\n\n- **API handler that sends a response with a 2-arg `(request, response)` signature → `ERR_HTTP_HEADERS_SENT`.** The framework inspects `function.length`; a 2-arg handler is treated as passive, so it auto-calls `next()` after your function resolves and `apiResponse` tries to send headers again. If you call `response.json()` / `response.send()` / `response.redirect()`, declare the third `next` parameter even if you never call it — the 3-arg signature disables auto-next. See [wiki/middleware-system.md → Active vs passive middleware](wiki/middleware-system.md#active-vs-passive-middleware-2-arg-vs-3-arg).\n- **Chaining `.where()` or `.orderBy()` directly off `.on()` in a query-builder JOIN → `where is not a function` at runtime.** `.on()` returns a `Node`; `.where()` and `.orderBy()` live on `Query`/`SelectQuery`, not `Node`. Hold the query handle in a variable and call `.where()` / `.orderBy()` on it separately. The `.where().and().execute()` chain works fine (Node has `.and()` and `.execute()`) — the trap is only joins. See [wiki/database.md → What chains on what](wiki/database.md#what-chains-on-what-the-gotcha).\n- **Passing `(column, alias)` to the top-level `select(...)` → silent column rename → `column \"X\" does not exist` at runtime.** The top-level `select(...)` is *variadic over columns* — `select('foo.uuid', 'method_uuid')` treats both strings as columns, not as `(column, alias)`. Only the chained `.select(col, alias)` form supports aliasing. Use `select().from(table).select(col, alias)` instead. See [wiki/database.md → `select(...)` is variadic](wiki/database.md#select-is-variadic--it-does-not-take-column-alias).\n- **Passing `{ isSQL: true, value: '...' }` to `.given()` for raw SQL in UPDATE/INSERT → `invalid input syntax for type ...` at runtime.** `UpdateQuery.given` / `InsertQuery.given` call `toString(value)` on every entry, which JSON-stringifies object values. The `{isSQL, value}` raw-escape convention is **only** honored inside `.where()` / `Leaf` / `RawLeaf`, not for SET / VALUES. When you need raw SQL on the write side (`COALESCE(col, NOW())`, `col + 1`, `gen_random_uuid()`), drop to `connection.query()` with bind parameters for just the user values. Canonical pattern: `oms/services/updateShipmentStatus.ts:79-100`.\n- **`.execute(connection)` / `.load(connection)` on a fresh `getConnection()` PoolClient before `startTransaction(connection)` → `Release called on client which has already been released to the pool` at runtime.** The query-builder's internal `release()` only short-circuits when `connection.INTRANSACTION === true`, a flag exclusively set by `startTransaction`. Pre-tx reads on a freshly-acquired PoolClient auto-release it back to the pool, and the next `startTransaction(connection)` operates on a detached client. Rule: either call `startTransaction` IMMEDIATELY after `getConnection`, or run pre-tx reads on the shared `pool` (which `release()` ignores) and acquire the dedicated PoolClient only at the top of the tx. The canonical \"delayed tx\" pattern (necessary when an external network call has to run between read and write — e.g. `carrier.createLabel()`) is in `oms/services/createShipment.ts:330-410`.\n- **Hook called after a conditional early return in a React component → `Rendered more hooks than during the previous render`.** All hooks must run in the same order on every render. If one render takes an early return before a `useEffect` and the next render reaches it, React errors. Move every hook above any conditional return.\n- **`.admin.graphql` type referenced from a non-admin `.graphql` file → \"Unknown type X\" at storefront schema build.** `buildStoreFrontSchema` filters out `.admin.graphql`; types defined there aren't visible to the storefront schema. Either move the type to a non-admin file or mark the referencing file `.admin.graphql` too. The two schemas build separately — admin sees both, storefront sees only non-admin.\n- **Dropping a DB column without grepping across modules.** EverShop modules share tables. A resolver in `modules/base/` may read a column owned by `modules/checkout/`. When dropping a column, `grep -rn \"table\\\\.column\" packages/evershop/src` across the whole tree, not just the owning module.\n- **New `.js` files in new code paths.** The codebase has mixed `.js` and `.ts` because the migration to TypeScript is incremental, but **new authorship is `.ts`** (or `.tsx` for React). Editing an existing `.js` keeps it `.js` for small changes; full rewrites are a good moment to switch. See [wiki/module-structure.md → TypeScript by default](wiki/module-structure.md#typescript-by-default).\n- **`hookable()` keys hooks by the wrapped function's `.name`, so a `…Impl` declaration silently kills its public hooks.** `hookable(fooImpl)` registers under `'fooImpl'`, but a `hookBeforeFoo` helper that calls `hookBefore('foo', …)` registers under `'foo'` — they never meet, the hook never fires, and nothing errors (the wrapped function still runs, the transaction still commits). Wrap a **named function expression** whose intrinsic name *is* the hook key, even if the binding differs: `const fooImpl = async function foo() {…}` (the `checkout.ts:10` idiom — `const _checkout = async function checkout(`). A plain `function fooImpl() {}` declaration sets `.name = 'fooImpl'` and breaks it. See [wiki/hooks.md → Common pitfalls](wiki/hooks.md#common-pitfalls); guard test `modules/oms/tests/unit/hookNameAlignment.test.js`.\n- **A widget `settingComponent` that reads a list setting as `watch('settings.x') ?? initial` works in the page-builder drawer but throws `items.map is not a function` on the legacy `/admin/widgets/edit` page.** The two surfaces seed settings differently: the drawer's page-level form holds real arrays/objects, but the legacy `<Form>` seeds list fields as a JSON **string** via a hidden `defaultValue={JSON.stringify(...)}` input — and `??` only guards null, so the string reaches `RepeatableAccordion` and would also fail the widget's AJV array schema on save (settings are never parsed in the save path). Read list settings with `useArraySetting('settings.x', initial)` and mutate via `asArray(getValues('settings.x'), initial)` (both from `@components/common/page-builder`), or hold the array with `useFieldArray` like `SlideshowSetting`. See [wiki/page-builder.md → Widget settings run on two surfaces](wiki/page-builder.md#widget-settings-run-on-two-surfaces-list-field-trap).\n\n## Doing work in this repo\n\n- The published package is built from `src/` to `dist/` via SWC (`npm run compile`). Runtime loads `.js` from `dist/`. When editing, edit `.ts` in `src/`.\n- Tests run with Jest: `npm test` from the repo root.\n- Lint with `npm run lint`.\n- Dev server: `npm run dev` (uses `webpack-dev-middleware` + HMR).\n- Build for production: `npm run build` then `npm run start`.\n- Never bypass `husky` hooks (`--no-verify`) or skip type/lint failures without an explicit go-ahead.\n","packages/create-evershop-app/README.md":"# create-evershop-app\n\nThis package includes the global command for [Create EverShop App](https://evershop.io/).<br> Please refer to its documentation:\n\n- [Getting Started](https://evershop.io/docs/development/getting-started/introduction) – How to create a new app.\n- [Development Guide](https://evershop.io/docs/development/) – How to develop an ecommerce web app with EverShop.\n","packages/create-evershop-app/sample/extensions/sample/Readme.md":"# Sample Extension\n\nThis is a sample extension for Evershop. It demonstrates how to build a simple extension for your Evershop store.\n\n## Enable/Disable the extension\n\nTo enable the extension, modify the configuration file `config/default.json` and set the `enabled` property to `true`:\n\n```json\n{\n  \"system\": {\n    \"extensions\": [\n      {\n        \"name\": \"sample\",\n        \"resolve\": \"extensions/sample\",\n        \"enabled\": true\n      }\n    ]\n  }\n}\n```\n\n> **Warning**\n> Enable/disable the extension requires running the command `npm run build` again.\n","packages/evershop/README.md":"<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</p>\n<p align=\"center\">\n<img width=\"60\" height=\"68\" alt=\"EverShop Logo\" src=\"https://raw.githubusercontent.com/evershopcommerce/evershop/dev/.github/images/logo-green.png\"/>\n</p>\n<p align=\"center\">\n  <h1 align=\"center\">EverShop</h1>\n</p>\n<h4 align=\"center\">\n    <a href=\"https://evershop.io/docs/development/getting-started/introduction\">Documentation</a> |\n    <a href=\"https://demo.evershop.io/\">Demo</a>\n</h4>\n\n<p align=\"center\">\n  <img src=\"https://github.com/evershopcommerce/evershop/actions/workflows/build_test.yml/badge.svg\" alt=\"Github Action\">\n  <a href=\"https://twitter.com/evershopjs\">\n    <img alt=\"Twitter Follow\" src=\"https://img.shields.io/twitter/follow/evershopjs?style=social\">\n  </a>\n  <a href=\"https://discord.gg/GSzt7dt7RM\">\n    <img src=\"https://img.shields.io/discord/757179260417867879?label=discord\" alt=\"Discord\">\n  </a>\n  <a href=\"https://opensource.org/licenses/GPL-3.0\">\n    <img src=\"https://img.shields.io/badge/License-GPLv3-blue.svg\" alt=\"License\">\n  </a>\n</p>\n\n<p align=\"center\">\n<img alt=\"EverShop\" width=\"950\" src=\"https://raw.githubusercontent.com/evershopcommerce/evershop/dev/.github/images/banner.png\"/>\n</p>\n\n## Introduction\n\nEverShop is a modern, TypeScript-first eCommerce platform built with GraphQL and React. Designed for developers, it offers essential commerce features in a modular, fully customizable architecture—perfect for building tailored shopping experiences with confidence and speed.\n\n## Installation Using Docker\n\nYou can get started with EverShop in minutes by using the Docker image. The Docker image is a great way to get started with EverShop without having to worry about installing dependencies or configuring your environment.\n\n```bash\ncurl -sSL https://raw.githubusercontent.com/evershopcommerce/evershop/main/docker-compose.yml > docker-compose.yml\ndocker-compose up -d\n```\n\nFor the full installation guide, please refer to our [Installation guide](https://evershop.io/docs/development/getting-started/installation-guide).\n\n## Documentation\n\n- [Installation guide](https://evershop.io/docs/development/getting-started/installation-guide).\n\n- [Extension development](https://evershop.io/docs/development/module/create-your-first-extension).\n\n- [Theme development](https://evershop.io/docs/development/theme/theme-overview).\n\n## Demo\n\nExplore our demo store.\n\n<p align=\"left\">\n  <a href=\"https://demo.evershop.io/admin\" target=\"_blank\">\n    <img alt=\"evershop-backend-demo\" height=\"35\" alt=\"EverShop Admin Demo\" src=\"https://raw.githubusercontent.com/evershopcommerce/evershop/dev/.github/images/evershop-demo-back.png\"/>\n  </a>\n  <a href=\"https://demo.evershop.io/\" target=\"_blank\">\n    <img alt=\"evershop-store-demo\" height=\"35\" alt=\"EverShop Store Demo\" src=\"https://raw.githubusercontent.com/evershopcommerce/evershop/dev/.github/images/evershop-demo-front.png\"/>\n  </a>\n</p>\n<b>Demo user:</b>\n\nEmail: demo@evershop.io<br/>\nPassword: 123456\n\n## Support\n\nIf you like my work, feel free to:\n\n- ⭐ this repository. It helps.\n- [![Tweet](https://img.shields.io/twitter/url/http/shields.io.svg?style=social)][tweet] about EverShop. Thank you!\n\n[tweet]: https://twitter.com/intent/tweet?url=https%3A%2F%2Fgithub.com%2Fevershopcommerce%2Fevershop&text=Awesome%20React%20Ecommerce%20Project&hashtags=react,ecommerce,expressjs,graphql\n\n## Contributing\n\nEverShop is an open-source project. We are committed to a fully transparent development process and appreciate highly any contributions. Whether you are helping us fix bugs, proposing new features, improving our documentation or spreading the word - we would love to have you as part of the EverShop community.\n\n### Ask a question about EverShop\n\nYou can ask questions, and participate in discussions about EverShop-related topics in the EverShop Discord channel.\n\n<a href=\"https://discord.gg/GSzt7dt7RM\"><img src=\"https://raw.githubusercontent.com/evershopcommerce/evershop/dev/.github/images/discord_banner_github.svg\" /></a>\n\n### Create a bug report\n\nIf you see an error message or run into an issue, please [create bug report](https://github.com/evershopcommerce/evershop/issues/new). This effort is valued and it will help all EverShop users.\n\n### Submit a feature request\n\nIf you have an idea, or you're missing a capability that would make development easier and more robust, please [Submit feature request](https://github.com/evershopcommerce/evershop/issues/new).\n\nIf a similar feature request already exists, don't forget to leave a \"+1\".\nIf you add some more information such as your thoughts and vision about the feature, your comments will be embraced warmly :)\n\nPlease refer to our [Contribution Guidelines](./CONTRIBUTING.md) and [Code of Conduct](./CODE_OF_CONDUCT.md).\n\n## License\n\n[GPL-3.0 License](https://github.com/evershopcommerce/evershop/blob/main/LICENSE)\n","packages/postgres-query-builder/README.md":"# PostgreSQL query builder for Node\n\nA PostgreSQL query builder for NodeJS.\n\n## Installation\n\n```javascript\nnpm install @evershop/postgres-query-builder\n```\n\n## Usage guide\n\nIt implements async/await.\n\n### Simple select\n\n```javascript\nconst { select } = require('@evershop/postgres-query-builder');\n\nconst products = await select('*')\n  .from('product')\n  .where('product_id', '>', 1)\n  .execute(pool);\n```\n\n### More complex where\n\n```javascript\nconst { select } = require('@evershop/postgres-query-builder');\n\nconst products = await select('*')\n  .from('product')\n  .where('product_id', '>', 1)\n  .and('sku', 'LIKE', 'sku')\n  .execute(pool);\n```\n\n### Event more complex where\n\n```javascript\nconst { select } = require('@evershop/postgres-query-builder');\n\nconst query = select('*').from('product');\nquery.where('product_id', '>', 1).and('sku', 'LIKE', 'sku');\nquery.orWhere('price', '>', 100);\n\nconst products = await query.execute(pool);\n```\n\n### Join table\n\n```javascript\nconst { select } = require('@evershop/postgres-query-builder');\n\nconst query = select('*').from('product');\nquery.leftJoin('price').on('product.`product_id`', '=', 'price.`product_id`');\nquery.where('product_id', '>', 1).and('sku', 'LIKE', 'sku');\nquery.andWhere('price', '>', 100);\n\nconst products = await query.execute(pool);\n```\n\n### Insert&update\n\n<table>\n<tr>\n<th> user_id </th>\n<th> name </th>\n<th> email </th>\n<th> phone </th>\n<th> status </th>\n</tr>\n<tr>\n<td>\n  1\n</td>\n<td>\n  David\n</td>\n<td>\n  emai@email.com\n</td>\n<td>\n  123456\n</td>\n<td>\n  1\n</td>\n</tr>\n</table>\n\n````javascript\n```javascript\nconst {insert} = require('@evershop/postgres-query-builder')\n\nconst query = insert(\"user\")\n.given({name: \"David\", email: \"email@email.com\", \"phone\": \"123456\", status: 1, notExistedColumn: \"This will not be a part of the query\"});\nawait query.execute(pool);\n````\n\n```javascript\nconst { update } = require('@evershop/postgres-query-builder');\n\nconst query = update('user')\n  .given({\n    name: 'David',\n    email: 'email@email.com',\n    phone: '123456',\n    status: 1,\n    notExistedColumn: 'This will not be a part of query'\n  })\n  .where('user_id', '=', 1);\nawait query.execute(pool);\n```\n\n### Working with transaction\n\n```javascript\nconst { Pool } = require('pg');\nconst {\n  insert,\n  getConnection,\n  startTransaction,\n  commit,\n  rollback\n} = require('@evershop/postgres-query-builder');\n\nconst pool = new Pool(connectionSetting);\n\n// Create a connection from the pool\nconst connection = await getConnection(pool);\n\n// Start a transaction\nawait startTransaction(connection);\ntry {\n  await insert('user')\n    .given({\n      name: 'David',\n      email: 'email@email.com',\n      phone: '123456',\n      status: 1,\n      notExistedColumn: 'This will not be a part of the query'\n    })\n    .execute(connection);\n  await commit(connection);\n} catch (e) {\n  await rollback(connection);\n}\n```\n\n## Security\n\nAll user provided data will be escaped.\n"},"items":[{"name":"CLAUDE.md","path":"CLAUDE.md","rawUrl":"https://raw.githubusercontent.com/evershopcommerce/evershop/HEAD/CLAUDE.md","title":"Claude Agent Guidelines & System Prompt","category":"claude-rule","format":"markdown","content":"# EverShop Core — Project Instructions for Claude\n\nThis is the **EverShop core repository** — the codebase for the modular monolith eCommerce platform built on Express + React (SSR) + PostgreSQL + GraphQL. The package source lives at `packages/evershop/src/` and is published as `@evershop/evershop`.\n\nThe author and maintainer is The Nguyen (`support@evershop.io`). Assume deep familiarity with the codebase.\n\n## Read the wiki first\n\nA curated wiki for this codebase lives in `wiki/`. **Before answering architectural questions or making non-trivial changes, read the relevant wiki page(s)**, not just the docs in `../docs/` or the source code. The wiki is hand-curated to be the fastest source of truth for \"how does this actually work\" questions.\n\n- `wiki/index.md` — catalog of all pages with one-line summaries. Read this first to find the right page.\n- `wiki/log.md` — chronological record of ingests, queries, and audits.\n- `wiki/<topic>.md` — the content pages.\n\nIf a page doesn't exist for the topic you need, that's a signal to **ingest** (see Operations below).\n\n## Operations\n\n### Query\n\nWhen the user asks a question that the wiki could answer:\n\n1. Open `wiki/index.md` and find candidate pages.\n2. Read those pages.\n3. Answer using the wiki content. Cite pages by filename (e.g., \"see `wiki/widgets.md`\") so the user can jump in.\n4. If the wiki content is **outdated relative to the code** (rename, removal, signature change), update the wiki page in the same response and append a note to `wiki/log.md`.\n\n### Ingest\n\nWhen the user explains something non-obvious about the codebase, or when you investigate an unfamiliar subsystem and the answer is worth keeping:\n\n1. Discuss the takeaways with the user inline (don't go silent for minutes writing files).\n2. Decide whether the knowledge belongs on an existing page or warrants a new one. Prefer updating existing pages — a page with five short sections beats five tiny pages.\n3. Write/update the page using the conventions below.\n4. Update `wiki/index.md` if a new page was added or a description changed.\n5. Append a one-line entry to `wiki/log.md` with prefix `## [YYYY-MM-DD] ingest | <topic>`.\n\n### Lint\n\nWhen asked to audit the wiki, or when you notice drift while answering questions:\n\n- Verify file paths and line references still resolve (they decay as files move).\n- Check that named functions/flags/files referenced in the wiki still exist (`grep`, `Read`).\n- Reconcile contradictions between pages.\n- Flag pages that haven't been touched in a long time *and* describe an area that has clearly evolved (use `git log --oneline -- <path>` to spot churn).\n- Append a `## [YYYY-MM-DD] lint | <scope>` entry to `wiki/log.md` summarizing what was checked and what changed.\n\n## Page conventions\n\nEvery page follows this shape:\n\n```md\n# <Title>\n\n**TL;DR.** One paragraph. The thing the user came here to learn, said directly.\n\n## <Section>\n\nBody. Code snippets go in fenced blocks with the language tag. File references use `relative/path:line` format so the user can click into them.\n\n## See also\n- [Other page](other-page.md) — one-line hook\n```\n\nSpecifics:\n\n- **File paths.** Always relative to the package root (`packages/evershop/src/...`) unless the file lives outside that tree. Add `:line` suffix when pointing at a specific implementation.\n- **Code samples.** Prefer real, compilable snippets pulled from the codebase over invented examples. If you must invent, mark it clearly.\n- **No marketing.** No \"powerful\", \"robust\", \"comprehensive\". Just what it is and how it works.\n- **Be willing to contradict the public docs.** If `../docs/` is wrong, the wiki should say so and explain the actual current behavior.\n- **Date format.** ISO `YYYY-MM-DD` everywhere.\n\n## EverShop quick reference\n\nFor deep understanding, read the wiki pages. This section is the cheat sheet.\n\n### Stack\n- **Runtime:** Node.js ≥ 20, Express, React 18 with SSR + hydration\n- **Database:** PostgreSQL 13+ (no other DBs supported; SQL is plain Postgres)\n- **GraphQL:** schema assembled at startup from per-module `.graphql` files\n- **Bundler:** webpack 5 with SWC for transforms (no Babel)\n- **Forms:** react-hook-form (wrapped by `components/common/form/Form.tsx`)\n- **Styling:** Tailwind v4 + PostCSS + custom plugins\n\n### Application type\nMulti-page application (MPA) — each route gets its own bundle and a full HTML response. Hydrated on the client. Not a SPA — there is no client-side router.\n\n### File / folder conventions\n- **Migrations:** `Version-X.Y.Z.ts` (hyphen, not underscore) in `<module>/migration/`\n- **Routes:** folder name = route ID, alphabetic only (a-z, A-Z), `route.json` declares the route\n- **Middleware:** lowercase first letter, bracket-syntax ordering `[after]name[before].ts`\n- **Master components:** uppercase first letter, `.tsx`, optional `export const layout = { areaId, sortOrder }`\n- **Shared between routes:** folder named `routeA+routeB/` (e.g. `productEdit+productNew/`)\n- **Site-wide middleware:** `pages/admin/all/`, `pages/frontStore/all/`, `pages/global/`, `api/global/`\n- **Subscribers:** `subscribers/<event_name>/<handler>.ts`\n- **Modules:** core in `packages/evershop/src/modules/`, user extensions in `extensions/` (project root)\n- **Module ID:** must be unique across the system\n\n### Bootstrap is a hard wall\nThe hook system and registry are **locked** after every module's `bootstrap.ts` runs. Calling `addProcessor`, `hookBefore`, `hookAfter`, `registerWidget`, `registerJob`, `registerEmailService`, `registerPaymentMethod`, etc. from inside a middleware or request handler **throws**. Always register from `bootstrap.ts`.\n\n### Public import paths\nSee `wiki/reference.md` for the full table. The most common ones:\n\n```ts\nimport { select, insert, update, del, insertOnUpdate } from '@evershop/evershop/lib/postgres/query';\nimport { pool, getConnection } from '@evershop/evershop/lib/postgres';\nimport { addProcessor, getValue } from '@evershop/evershop/lib/util/registry';\nimport { hookBefore, hookAfter, hookable } from '@evershop/evershop/lib/util/hookable';\nimport { emit } from '@evershop/evershop/lib/event';\nimport { createSubscriber } from '@evershop/evershop/lib/event/subscriber';\nimport { buildUrl, buildAbsoluteUrl } from '@evershop/evershop/lib/router';\nimport { registerWidget } from '@evershop/evershop/lib/widget';\nimport { setContextValue, getContextValue } from '@evershop/evershop/graphql/services';\n```\n\n### Common pitfalls\n- `import { Request, Response } from 'express'` — wrong. Use `EvershopRequest`/`EvershopResponse` from `@evershop/evershop/types/request` and `types/response`.\n- `module.exports` — wrong. ESM. Use `export default`.\n- MySQL syntax — wrong. PostgreSQL. Use `IDENTITY` or `SERIAL`, double-quoted identifiers, `JSONB`, `gen_random_uuid()`.\n- `migrations/` (plural) folder — wrong. Singular `migration/`.\n- `Version_1.0.0.ts` (underscore) — wrong. Hyphen: `Version-1.0.0.ts`.\n- `pages/frontend/` — wrong. `pages/frontStore/`.\n- Arrow functions in hookable / processor callbacks when context is needed — `this` is bound via `.call()`, arrow functions can't access it.\n- Adding a hook or processor from a middleware — locked after bootstrap, throws.\n\n### Common mistakes\n\nThe pitfalls above are syntactic — caught by lint or first compile. The ones below are runtime or integration traps. They compile cleanly and fail later. Each has bitten the codebase; the wiki pages explain *why* and show the fix.\n\n- **API handler that sends a response with a 2-arg `(request, response)` signature → `ERR_HTTP_HEADERS_SENT`.** The framework inspects `function.length`; a 2-arg handler is treated as passive, so it auto-calls `next()` after your function resolves and `apiResponse` tries to send headers again. If you call `response.json()` / `response.send()` / `response.redirect()`, declare the third `next` parameter even if you never call it — the 3-arg signature disables auto-next. See [wiki/middleware-system.md → Active vs passive middleware](wiki/middleware-system.md#active-vs-passive-middleware-2-arg-vs-3-arg).\n- **Chaining `.where()` or `.orderBy()` directly off `.on()` in a query-builder JOIN → `where is not a function` at runtime.** `.on()` returns a `Node`; `.where()` and `.orderBy()` live on `Query`/`SelectQuery`, not `Node`. Hold the query handle in a variable and call `.where()` / `.orderBy()` on it separately. The `.where().and().execute()` chain works fine (Node has `.and()` and `.execute()`) — the trap is only joins. See [wiki/database.md → What chains on what](wiki/database.md#what-chains-on-what-the-gotcha).\n- **Passing `(column, alias)` to the top-level `select(...)` → silent column rename → `column \"X\" does not exist` at runtime.** The top-level `select(...)` is *variadic over columns* — `select('foo.uuid', 'method_uuid')` treats both strings as columns, not as `(column, alias)`. Only the chained `.select(col, alias)` form supports aliasing. Use `select().from(table).select(col, alias)` instead. See [wiki/database.md → `select(...)` is variadic](wiki/database.md#select-is-variadic--it-does-not-take-column-alias).\n- **Passing `{ isSQL: true, value: '...' }` to `.given()` for raw SQL in UPDATE/INSERT → `invalid input syntax for type ...` at runtime.** `UpdateQuery.given` / `InsertQuery.given` call `toString(value)` on every entry, which JSON-stringifies object values. The `{isSQL, value}` raw-escape convention is **only** honored inside `.where()` / `Leaf` / `RawLeaf`, not for SET / VALUES. When you need raw SQL on the write side (`COALESCE(col, NOW())`, `col + 1`, `gen_random_uuid()`), drop to `connection.query()` with bind parameters for just the user values. Canonical pattern: `oms/services/updateShipmentStatus.ts:79-100`.\n- **`.execute(connection)` / `.load(connection)` on a fresh `getConnection()` PoolClient before `startTransaction(connection)` → `Release called on client which has already been released to the pool` at runtime.** The query-builder's internal `release()` only short-circuits when `connection.INTRANSACTION === true`, a flag exclusively set by `startTransaction`. Pre-tx reads on a freshly-acquired PoolClient auto-release it back to the pool, and the next `startTransaction(connection)` operates on a detached client. Rule: either call `startTransaction` IMMEDIATELY after `getConnection`, or run pre-tx reads on the shared `pool` (which `release()` ignores) and acquire the dedicated PoolClient only at the top of the tx. The canonical \"delayed tx\" pattern (necessary when an external network call has to run between read and write — e.g. `carrier.createLabel()`) is in `oms/services/createShipment.ts:330-410`.\n- **Hook called after a conditional early return in a React component → `Rendered more hooks than during the previous render`.** All hooks must run in the same order on every render. If one render takes an early return before a `useEffect` and the next render reaches it, React errors. Move every hook above any conditional return.\n- **`.admin.graphql` type referenced from a non-admin `.graphql` file → \"Unknown type X\" at storefront schema build.** `buildStoreFrontSchema` filters out `.admin.graphql`; types defined there aren't visible to the storefront schema. Either move the type to a non-admin file or mark the referencing file `.admin.graphql` too. The two schemas build separately — admin sees both, storefront sees only non-admin.\n- **Dropping a DB column without grepping across modules.** EverShop modules share tables. A resolver in `modules/base/` may read a column owned by `modules/checkout/`. When dropping a column, `grep -rn \"table\\\\.column\" packages/evershop/src` across the whole tree, not just the owning module.\n- **New `.js` files in new code paths.** The codebase has mixed `.js` and `.ts` because the migration to TypeScript is incremental, but **new authorship is `.ts`** (or `.tsx` for React). Editing an existing `.js` keeps it `.js` for small changes; full rewrites are a good moment to switch. See [wiki/module-structure.md → TypeScript by default](wiki/module-structure.md#typescript-by-default).\n- **`hookable()` keys hooks by the wrapped function's `.name`, so a `…Impl` declaration silently kills its public hooks.** `hookable(fooImpl)` registers under `'fooImpl'`, but a `hookBeforeFoo` helper that calls `hookBefore('foo', …)` registers under `'foo'` — they never meet, the hook never fires, and nothing errors (the wrapped function still runs, the transaction still commits). Wrap a **named function expression** whose intrinsic name *is* the hook key, even if the binding differs: `const fooImpl = async function foo() {…}` (the `checkout.ts:10` idiom — `const _checkout = async function checkout(`). A plain `function fooImpl() {}` declaration sets `.name = 'fooImpl'` and breaks it. See [wiki/hooks.md → Common pitfalls](wiki/hooks.md#common-pitfalls); guard test `modules/oms/tests/unit/hookNameAlignment.test.js`.\n- **A widget `settingComponent` that reads a list setting as `watch('settings.x') ?? initial` works in the page-builder drawer but throws `items.map is not a function` on the legacy `/admin/widgets/edit` page.** The two surfaces seed settings differently: the drawer's page-level form holds real arrays/objects, but the legacy `<Form>` seeds list fields as a JSON **string** via a hidden `defaultValue={JSON.stringify(...)}` input — and `??` only guards null, so the string reaches `RepeatableAccordion` and would also fail the widget's AJV array schema on save (settings are never parsed in the save path). Read list settings with `useArraySetting('settings.x', initial)` and mutate via `asArray(getValues('settings.x'), initial)` (both from `@components/common/page-builder`), or hold the array with `useFieldArray` like `SlideshowSetting`. See [wiki/page-builder.md → Widget settings run on two surfaces](wiki/page-builder.md#widget-settings-run-on-two-surfaces-list-field-trap).\n\n## Doing work in this repo\n\n- The published package is built from `src/` to `dist/` via SWC (`npm run compile`). Runtime loads `.js` from `dist/`. When editing, edit `.ts` in `src/`.\n- Tests run with Jest: `npm test` from the repo root.\n- Lint with `npm run lint`.\n- Dev server: `npm run dev` (uses `webpack-dev-middleware` + HMR).\n- Build for production: `npm run build` then `npm run start`.\n- Never bypass `husky` hooks (`--no-verify`) or skip type/lint failures without an explicit go-ahead.\n","isInternal":false,"tokens":3589,"sizeBytes":14443},{"name":"README.md","path":"packages/create-evershop-app/README.md","rawUrl":"https://raw.githubusercontent.com/evershopcommerce/evershop/HEAD/packages/create-evershop-app/README.md","title":"create-evershop-app Documentation","category":"plugin-manifest","format":"markdown","content":"# create-evershop-app\n\nThis package includes the global command for [Create EverShop App](https://evershop.io/).<br> Please refer to its documentation:\n\n- [Getting Started](https://evershop.io/docs/development/getting-started/introduction) – How to create a new app.\n- [Development Guide](https://evershop.io/docs/development/) – How to develop an ecommerce web app with EverShop.\n","isInternal":false,"tokens":96,"sizeBytes":385},{"name":"Readme.md","path":"packages/create-evershop-app/sample/extensions/sample/Readme.md","rawUrl":"https://raw.githubusercontent.com/evershopcommerce/evershop/HEAD/packages/create-evershop-app/sample/extensions/sample/Readme.md","title":"sample Documentation","category":"plugin-manifest","format":"markdown","content":"# Sample Extension\n\nThis is a sample extension for Evershop. It demonstrates how to build a simple extension for your Evershop store.\n\n## Enable/Disable the extension\n\nTo enable the extension, modify the configuration file `config/default.json` and set the `enabled` property to `true`:\n\n```json\n{\n  \"system\": {\n    \"extensions\": [\n      {\n        \"name\": \"sample\",\n        \"resolve\": \"extensions/sample\",\n        \"enabled\": true\n      }\n    ]\n  }\n}\n```\n\n> **Warning**\n> Enable/disable the extension requires running the command `npm run build` again.\n","isInternal":false,"tokens":138,"sizeBytes":552},{"name":"README.md","path":"packages/evershop/README.md","rawUrl":"https://raw.githubusercontent.com/evershopcommerce/evershop/HEAD/packages/evershop/README.md","title":"evershop Documentation","category":"plugin-manifest","format":"markdown","content":"<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</p>\n<p align=\"center\">\n<img width=\"60\" height=\"68\" alt=\"EverShop Logo\" src=\"https://raw.githubusercontent.com/evershopcommerce/evershop/dev/.github/images/logo-green.png\"/>\n</p>\n<p align=\"center\">\n  <h1 align=\"center\">EverShop</h1>\n</p>\n<h4 align=\"center\">\n    <a href=\"https://evershop.io/docs/development/getting-started/introduction\">Documentation</a> |\n    <a href=\"https://demo.evershop.io/\">Demo</a>\n</h4>\n\n<p align=\"center\">\n  <img src=\"https://github.com/evershopcommerce/evershop/actions/workflows/build_test.yml/badge.svg\" alt=\"Github Action\">\n  <a href=\"https://twitter.com/evershopjs\">\n    <img alt=\"Twitter Follow\" src=\"https://img.shields.io/twitter/follow/evershopjs?style=social\">\n  </a>\n  <a href=\"https://discord.gg/GSzt7dt7RM\">\n    <img src=\"https://img.shields.io/discord/757179260417867879?label=discord\" alt=\"Discord\">\n  </a>\n  <a href=\"https://opensource.org/licenses/GPL-3.0\">\n    <img src=\"https://img.shields.io/badge/License-GPLv3-blue.svg\" alt=\"License\">\n  </a>\n</p>\n\n<p align=\"center\">\n<img alt=\"EverShop\" width=\"950\" src=\"https://raw.githubusercontent.com/evershopcommerce/evershop/dev/.github/images/banner.png\"/>\n</p>\n\n## Introduction\n\nEverShop is a modern, TypeScript-first eCommerce platform built with GraphQL and React. Designed for developers, it offers essential commerce features in a modular, fully customizable architecture—perfect for building tailored shopping experiences with confidence and speed.\n\n## Installation Using Docker\n\nYou can get started with EverShop in minutes by using the Docker image. The Docker image is a great way to get started with EverShop without having to worry about installing dependencies or configuring your environment.\n\n```bash\ncurl -sSL https://raw.githubusercontent.com/evershopcommerce/evershop/main/docker-compose.yml > docker-compose.yml\ndocker-compose up -d\n```\n\nFor the full installation guide, please refer to our [Installation guide](https://evershop.io/docs/development/getting-started/installation-guide).\n\n## Documentation\n\n- [Installation guide](https://evershop.io/docs/development/getting-started/installation-guide).\n\n- [Extension development](https://evershop.io/docs/development/module/create-your-first-extension).\n\n- [Theme development](https://evershop.io/docs/development/theme/theme-overview).\n\n## Demo\n\nExplore our demo store.\n\n<p align=\"left\">\n  <a href=\"https://demo.evershop.io/admin\" target=\"_blank\">\n    <img alt=\"evershop-backend-demo\" height=\"35\" alt=\"EverShop Admin Demo\" src=\"https://raw.githubusercontent.com/evershopcommerce/evershop/dev/.github/images/evershop-demo-back.png\"/>\n  </a>\n  <a href=\"https://demo.evershop.io/\" target=\"_blank\">\n    <img alt=\"evershop-store-demo\" height=\"35\" alt=\"EverShop Store Demo\" src=\"https://raw.githubusercontent.com/evershopcommerce/evershop/dev/.github/images/evershop-demo-front.png\"/>\n  </a>\n</p>\n<b>Demo user:</b>\n\nEmail: demo@evershop.io<br/>\nPassword: 123456\n\n## Support\n\nIf you like my work, feel free to:\n\n- ⭐ this repository. It helps.\n- [![Tweet](https://img.shields.io/twitter/url/http/shields.io.svg?style=social)][tweet] about EverShop. Thank you!\n\n[tweet]: https://twitter.com/intent/tweet?url=https%3A%2F%2Fgithub.com%2Fevershopcommerce%2Fevershop&text=Awesome%20React%20Ecommerce%20Project&hashtags=react,ecommerce,expressjs,graphql\n\n## Contributing\n\nEverShop is an open-source project. We are committed to a fully transparent development process and appreciate highly any contributions. Whether you are helping us fix bugs, proposing new features, improving our documentation or spreading the word - we would love to have you as part of the EverShop community.\n\n### Ask a question about EverShop\n\nYou can ask questions, and participate in discussions about EverShop-related topics in the EverShop Discord channel.\n\n<a href=\"https://discord.gg/GSzt7dt7RM\"><img src=\"https://raw.githubusercontent.com/evershopcommerce/evershop/dev/.github/images/discord_banner_github.svg\" /></a>\n\n### Create a bug report\n\nIf you see an error message or run into an issue, please [create bug report](https://github.com/evershopcommerce/evershop/issues/new). This effort is valued and it will help all EverShop users.\n\n### Submit a feature request\n\nIf you have an idea, or you're missing a capability that would make development easier and more robust, please [Submit feature request](https://github.com/evershopcommerce/evershop/issues/new).\n\nIf a similar feature request already exists, don't forget to leave a \"+1\".\nIf you add some more information such as your thoughts and vision about the feature, your comments will be embraced warmly :)\n\nPlease refer to our [Contribution Guidelines](./CONTRIBUTING.md) and [Code of Conduct](./CODE_OF_CONDUCT.md).\n\n## License\n\n[GPL-3.0 License](https://github.com/evershopcommerce/evershop/blob/main/LICENSE)\n","isInternal":false,"tokens":1209,"sizeBytes":4839},{"name":"README.md","path":"packages/postgres-query-builder/README.md","rawUrl":"https://raw.githubusercontent.com/evershopcommerce/evershop/HEAD/packages/postgres-query-builder/README.md","title":"postgres-query-builder Documentation","category":"plugin-manifest","format":"markdown","content":"# PostgreSQL query builder for Node\n\nA PostgreSQL query builder for NodeJS.\n\n## Installation\n\n```javascript\nnpm install @evershop/postgres-query-builder\n```\n\n## Usage guide\n\nIt implements async/await.\n\n### Simple select\n\n```javascript\nconst { select } = require('@evershop/postgres-query-builder');\n\nconst products = await select('*')\n  .from('product')\n  .where('product_id', '>', 1)\n  .execute(pool);\n```\n\n### More complex where\n\n```javascript\nconst { select } = require('@evershop/postgres-query-builder');\n\nconst products = await select('*')\n  .from('product')\n  .where('product_id', '>', 1)\n  .and('sku', 'LIKE', 'sku')\n  .execute(pool);\n```\n\n### Event more complex where\n\n```javascript\nconst { select } = require('@evershop/postgres-query-builder');\n\nconst query = select('*').from('product');\nquery.where('product_id', '>', 1).and('sku', 'LIKE', 'sku');\nquery.orWhere('price', '>', 100);\n\nconst products = await query.execute(pool);\n```\n\n### Join table\n\n```javascript\nconst { select } = require('@evershop/postgres-query-builder');\n\nconst query = select('*').from('product');\nquery.leftJoin('price').on('product.`product_id`', '=', 'price.`product_id`');\nquery.where('product_id', '>', 1).and('sku', 'LIKE', 'sku');\nquery.andWhere('price', '>', 100);\n\nconst products = await query.execute(pool);\n```\n\n### Insert&update\n\n<table>\n<tr>\n<th> user_id </th>\n<th> name </th>\n<th> email </th>\n<th> phone </th>\n<th> status </th>\n</tr>\n<tr>\n<td>\n  1\n</td>\n<td>\n  David\n</td>\n<td>\n  emai@email.com\n</td>\n<td>\n  123456\n</td>\n<td>\n  1\n</td>\n</tr>\n</table>\n\n````javascript\n```javascript\nconst {insert} = require('@evershop/postgres-query-builder')\n\nconst query = insert(\"user\")\n.given({name: \"David\", email: \"email@email.com\", \"phone\": \"123456\", status: 1, notExistedColumn: \"This will not be a part of the query\"});\nawait query.execute(pool);\n````\n\n```javascript\nconst { update } = require('@evershop/postgres-query-builder');\n\nconst query = update('user')\n  .given({\n    name: 'David',\n    email: 'email@email.com',\n    phone: '123456',\n    status: 1,\n    notExistedColumn: 'This will not be a part of query'\n  })\n  .where('user_id', '=', 1);\nawait query.execute(pool);\n```\n\n### Working with transaction\n\n```javascript\nconst { Pool } = require('pg');\nconst {\n  insert,\n  getConnection,\n  startTransaction,\n  commit,\n  rollback\n} = require('@evershop/postgres-query-builder');\n\nconst pool = new Pool(connectionSetting);\n\n// Create a connection from the pool\nconst connection = await getConnection(pool);\n\n// Start a transaction\nawait startTransaction(connection);\ntry {\n  await insert('user')\n    .given({\n      name: 'David',\n      email: 'email@email.com',\n      phone: '123456',\n      status: 1,\n      notExistedColumn: 'This will not be a part of the query'\n    })\n    .execute(connection);\n  await commit(connection);\n} catch (e) {\n  await rollback(connection);\n}\n```\n\n## Security\n\nAll user provided data will be escaped.\n","isInternal":false,"tokens":731,"sizeBytes":2921}],"systemPromptSnippet":"<agent_rules repository=\"evershopcommerce/evershop\">\n\n<!-- Skill/Rule: Claude Agent Guidelines & System Prompt (CLAUDE.md) -->\n# EverShop Core — Project Instructions for Claude\n\nThis is the **EverShop core repository** — the codebase for the modular monolith eCommerce platform built on Express + React (SSR) + PostgreSQL + GraphQL. The package source lives at `packages/evershop/src/` and is published as `@evershop/evershop`.\n\nThe author and maintainer is The Nguyen (`support@evershop.io`). Assume deep familiarity with the codebase.\n\n## Read the wiki first\n\nA curated wiki for this codebase lives in `wiki/`. **Before answering architectural questions or making non-trivial changes, read the relevant wiki page(s)**, not just the docs in `../docs/` or the source code. The wiki is hand-curated to be the fastest source of truth for \"how does this actually work\" questions.\n\n- `wiki/index.md` — catalog of all pages with one-line summaries. Read this first to find the right page.\n- `wiki/log.md` — chronological record of ingests, queries, and audits.\n- `wiki/<topic>.md` — the content pages.\n\nIf a page doesn't exist for the topic you need, that's a signal to **ingest** (see Operations below).\n\n## Operations\n\n### Query\n\nWhen the user asks a question that the wiki could answer:\n\n1. Open `wiki/index.md` and find candidate pages.\n2. Read those pages.\n3. Answer using the wiki content. Cite pages by filename (e.g., \"see `wiki/widgets.md`\") so the user can jump in.\n4. If the wiki content is **outdated relative to the code** (rename, removal, signature change), update the wiki page in the same response and append a note to `wiki/log.md`.\n\n### Ingest\n\nWhen the user explains something non-obvious about the codebase, or when you investigate an unfamiliar subsystem and the answer is worth keeping:\n\n1. Discuss the takeaways with the user inline (don't go silent for minutes writing files).\n2. Decide whether the knowledge belongs on an existing page or warrants a new one. Prefer updating existing pages — a page with five short sections beats five tiny pages.\n3. Write/update the page using the conventions below.\n4. Update `wiki/index.md` if a new page was added or a description changed.\n5. Append a one-line entry to `wiki/log.md` with prefix `## [YYYY-MM-DD] ingest | <topic>`.\n\n### Lint\n\nWhen asked to audit the wiki, or when you notice drift while answering questions:\n\n- Verify file paths and line references still resolve (they decay as files move).\n- Check that named functions/flags/files referenced in the wiki still exist (`grep`, `Read`).\n- Reconcile contradictions between pages.\n- Flag pages that haven't been touched in a long time *and* describe an area that has clearly evolved (use `git log --oneline -- <path>` to spot churn).\n- Append a `## [YYYY-MM-DD] lint | <scope>` entry to `wiki/log.md` summarizing what was checked and what changed.\n\n## Page conventions\n\nEvery page follows this shape:\n\n```md\n# <Title>\n\n**TL;DR.** One paragraph. The thing the user came here to learn, said directly.\n\n## <Section>\n\nBody. Code snippets go in fenced blocks with the language tag. File references use `relative/path:line` format so the user can click into them.\n\n## See also\n- [Other page](other-page.md) — one-line hook\n```\n\nSpecifics:\n\n- **File paths.** Always relative to the package root (`packages/evershop/src/...`) unless the file lives outside that tree. Add `:line` suffix when pointing at a specific implementation.\n- **Code samples.** Prefer real, compilable snippets pulled from the codebase over invented examples. If you must invent, mark it clearly.\n- **No marketing.** No \"powerful\", \"robust\", \"comprehensive\". Just what it is and how it works.\n- **Be willing to contradict the public docs.** If `../docs/` is wrong, the wiki should say so and explain the actual current behavior.\n- **Date format.** ISO `YYYY-MM-DD` everywhere.\n\n## EverShop quick reference\n\nFor deep understanding, read the wiki pages. This section is the cheat sheet.\n\n### Stack\n- **Runtime:** Node.js ≥ 20, Express, React 18 with SSR + hydration\n- **Database:** PostgreSQL 13+ (no other DBs supported; SQL is plain Postgres)\n- **GraphQL:** schema assembled at startup from per-module `.graphql` files\n- **Bundler:** webpack 5 with SWC for transforms (no Babel)\n- **Forms:** react-hook-form (wrapped by `components/common/form/Form.tsx`)\n- **Styling:** Tailwind v4 + PostCSS + custom plugins\n\n### Application type\nMulti-page application (MPA) — each route gets its own bundle and a full HTML response. Hydrated on the client. Not a SPA — there is no client-side router.\n\n### File / folder conventions\n- **Migrations:** `Version-X.Y.Z.ts` (hyphen, not underscore) in `<module>/migration/`\n- **Routes:** folder name = route ID, alphabetic only (a-z, A-Z), `route.json` declares the route\n- **Middleware:** lowercase first letter, bracket-syntax ordering `[after]name[before].ts`\n- **Master components:** uppercase first letter, `.tsx`, optional `export const layout = { areaId, sortOrder }`\n- **Shared between routes:** folder named `routeA+routeB/` (e.g. `productEdit+productNew/`)\n- **Site-wide middleware:** `pages/admin/all/`, `pages/frontStore/all/`, `pages/global/`, `api/global/`\n- **Subscribers:** `subscribers/<event_name>/<handler>.ts`\n- **Modules:** core in `packages/evershop/src/modules/`, user extensions in `extensions/` (project root)\n- **Module ID:** must be unique across the system\n\n### Bootstrap is a hard wall\nThe hook system and registry are **locked** after every module's `bootstrap.ts` runs. Calling `addProcessor`, `hookBefore`, `hookAfter`, `registerWidget`, `registerJob`, `registerEmailService`, `registerPaymentMethod`, etc. from inside a middleware or request handler **throws**. Always register from `bootstrap.ts`.\n\n### Public import paths\nSee `wiki/reference.md` for the full table. The most common ones:\n\n```ts\nimport { select, insert, update, del, insertOnUpdate } from '@evershop/evershop/lib/postgres/query';\nimport { pool, getConnection } from '@evershop/evershop/lib/postgres';\nimport { addProcessor, getValue } from '@evershop/evershop/lib/util/registry';\nimport { hookBefore, hookAfter, hookable } from '@evershop/evershop/lib/util/hookable';\nimport { emit } from '@evershop/evershop/lib/event';\nimport { createSubscriber } from '@evershop/evershop/lib/event/subscriber';\nimport { buildUrl, buildAbsoluteUrl } from '@evershop/evershop/lib/router';\nimport { registerWidget } from '@evershop/evershop/lib/widget';\nimport { setContextValue, getContextValue } from '@evershop/evershop/graphql/services';\n```\n\n### Common pitfalls\n- `import { Request, Response } from 'express'` — wrong. Use `EvershopRequest`/`EvershopResponse` from `@evershop/evershop/types/request` and `types/response`.\n- `module.exports` — wrong. ESM. Use `export default`.\n- MySQL syntax — wrong. PostgreSQL. Use `IDENTITY` or `SERIAL`, double-quoted identifiers, `JSONB`, `gen_random_uuid()`.\n- `migrations/` (plural) folder — wrong. Singular `migration/`.\n- `Version_1.0.0.ts` (underscore) — wrong. Hyphen: `Version-1.0.0.ts`.\n- `pages/frontend/` — wrong. `pages/frontStore/`.\n- Arrow functions in hookable / processor callbacks when context is needed — `this` is bound via `.call()`, arrow functions can't access it.\n- Adding a hook or processor from a middleware — locked after bootstrap, throws.\n\n### Common mistakes\n\nThe pitfalls above are syntactic — caught by lint or first compile. The ones below are runtime or integration traps. They compile cleanly and fail later. Each has bitten the codebase; the wiki pages explain *why* and show the fix.\n\n- **API handler that sends a response with a 2-arg `(request, response)` signature → `ERR_HTTP_HEADERS_SENT`.** The framework inspects `function.length`; a 2-arg handler is treated as passive, so it auto-calls `next()` after your function resolves and `apiResponse` tries to send headers again. If you call `response.json()` / `response.send()` / `response.redirect()`, declare the third `next` parameter even if you never call it — the 3-arg signature disables auto-next. See [wiki/middleware-system.md → Active vs passive middleware](wiki/middleware-system.md#active-vs-passive-middleware-2-arg-vs-3-arg).\n- **Chaining `.where()` or `.orderBy()` directly off `.on()` in a query-builder JOIN → `where is not a function` at runtime.** `.on()` returns a `Node`; `.where()` and `.orderBy()` live on `Query`/`SelectQuery`, not `Node`. Hold the query handle in a variable and call `.where()` / `.orderBy()` on it separately. The `.where().and().execute()` chain works fine (Node has `.and()` and `.execute()`) — the trap is only joins. See [wiki/database.md → What chains on what](wiki/database.md#what-chains-on-what-the-gotcha).\n- **Passing `(column, alias)` to the top-level `select(...)` → silent column rename → `column \"X\" does not exist` at runtime.** The top-level `select(...)` is *variadic over columns* — `select('foo.uuid', 'method_uuid')` treats both strings as columns, not as `(column, alias)`. Only the chained `.select(col, alias)` form supports aliasing. Use `select().from(table).select(col, alias)` instead. See [wiki/database.md → `select(...)` is variadic](wiki/database.md#select-is-variadic--it-does-not-take-column-alias).\n- **Passing `{ isSQL: true, value: '...' }` to `.given()` for raw SQL in UPDATE/INSERT → `invalid input syntax for type ...` at runtime.** `UpdateQuery.given` / `InsertQuery.given` call `toString(value)` on every entry, which JSON-stringifies object values. The `{isSQL, value}` raw-escape convention is **only** honored inside `.where()` / `Leaf` / `RawLeaf`, not for SET / VALUES. When you need raw SQL on the write side (`COALESCE(col, NOW())`, `col + 1`, `gen_random_uuid()`), drop to `connection.query()` with bind parameters for just the user values. Canonical pattern: `oms/services/updateShipmentStatus.ts:79-100`.\n- **`.execute(connection)` / `.load(connection)` on a fresh `getConnection()` PoolClient before `startTransaction(connection)` → `Release called on client which has already been released to the pool` at runtime.** The query-builder's internal `release()` only short-circuits when `connection.INTRANSACTION === true`, a flag exclusively set by `startTransaction`. Pre-tx reads on a freshly-acquired PoolClient auto-release it back to the pool, and the next `startTransaction(connection)` operates on a detached client. Rule: either call `startTransaction` IMMEDIATELY after `getConnection`, or run pre-tx reads on the shared `pool` (which `release()` ignores) and acquire the dedicated PoolClient only at the top of the tx. The canonical \"delayed tx\" pattern (necessary when an external network call has to run between read and write — e.g. `carrier.createLabel()`) is in `oms/services/createShipment.ts:330-410`.\n- **Hook called after a conditional early return in a React component → `Rendered more hooks than during the previous render`.** All hooks must run in the same order on every render. If one render takes an early return before a `useEffect` and the next render reaches it, React errors. Move every hook above any conditional return.\n- **`.admin.graphql` type referenced from a non-admin `.graphql` file → \"Unknown type X\" at storefront schema build.** `buildStoreFrontSchema` filters out `.admin.graphql`; types defined there aren't visible to the storefront schema. Either move the type to a non-admin file or mark the referencing file `.admin.graphql` too. The two schemas build separately — admin sees both, storefront sees only non-admin.\n- **Dropping a DB column without grepping across modules.** EverShop modules share tables. A resolver in `modules/base/` may read a column owned by `modules/checkout/`. When dropping a column, `grep -rn \"table\\\\.column\" packages/evershop/src` across the whole tree, not just the owning module.\n- **New `.js` files in new code paths.** The codebase has mixed `.js` and `.ts` because the migration to TypeScript is incremental, but **new authorship is `.ts`** (or `.tsx` for React). Editing an existing `.js` keeps it `.js` for small changes; full rewrites are a good moment to switch. See [wiki/module-structure.md → TypeScript by default](wiki/module-structure.md#typescript-by-default).\n- **`hookable()` keys hooks by the wrapped function's `.name`, so a `…Impl` declaration silently kills its public hooks.** `hookable(fooImpl)` registers under `'fooImpl'`, but a `hookBeforeFoo` helper that calls `hookBefore('foo', …)` registers under `'foo'` — they never meet, the hook never fires, and nothing errors (the wrapped function still runs, the transaction still commits). Wrap a **named function expression** whose intrinsic name *is* the hook key, even if the binding differs: `const fooImpl = async function foo() {…}` (the `checkout.ts:10` idiom — `const _checkout = async function checkout(`). A plain `function fooImpl() {}` declaration sets `.name = 'fooImpl'` and breaks it. See [wiki/hooks.md → Common pitfalls](wiki/hooks.md#common-pitfalls); guard test `modules/oms/tests/unit/hookNameAlignment.test.js`.\n- **A widget `settingComponent` that reads a list setting as `watch('settings.x') ?? initial` works in the page-builder drawer but throws `items.map is not a function` on the legacy `/admin/widgets/edit` page.** The two surfaces seed settings differently: the drawer's page-level form holds real arrays/objects, but the legacy `<Form>` seeds list fields as a JSON **string** via a hidden `defaultValue={JSON.stringify(...)}` input — and `??` only guards null, so the string reaches `RepeatableAccordion` and would also fail the widget's AJV array schema on save (settings are never parsed in the save path). Read list settings with `useArraySetting('settings.x', initial)` and mutate via `asArray(getValues('settings.x'), initial)` (both from `@components/common/page-builder`), or hold the array with `useFieldArray` like `SlideshowSetting`. See [wiki/page-builder.md → Widget settings run on two surfaces](wiki/page-builder.md#widget-settings-run-on-two-surfaces-list-field-trap).\n\n## Doing work in this repo\n\n- The published package is built from `src/` to `dist/` via SWC (`npm run compile`). Runtime loads `.js` from `dist/`. When editing, edit `.ts` in `src/`.\n- Tests run with Jest: `npm test` from the repo root.\n- Lint with `npm run lint`.\n- Dev server: `npm run dev` (uses `webpack-dev-middleware` + HMR).\n- Build for production: `npm run build` then `npm run start`.\n- Never bypass `husky` hooks (`--no-verify`) or skip type/lint failures without an explicit go-ahead.\n\n\n<!-- Skill/Rule: create-evershop-app Documentation (packages/create-evershop-app/README.md) -->\n# create-evershop-app\n\nThis package includes the global command for [Create EverShop App](https://evershop.io/).<br> Please refer to its documentation:\n\n- [Getting Started](https://evershop.io/docs/development/getting-started/introduction) – How to create a new app.\n- [Development Guide](https://evershop.io/docs/development/) – How to develop an ecommerce web app with EverShop.\n\n\n<!-- Skill/Rule: sample Documentation (packages/create-evershop-app/sample/extensions/sample/Readme.md) -->\n# Sample Extension\n\nThis is a sample extension for Evershop. It demonstrates how to build a simple extension for your Evershop store.\n\n## Enable/Disable the extension\n\nTo enable the extension, modify the configuration file `config/default.json` and set the `enabled` property to `true`:\n\n```json\n{\n  \"system\": {\n    \"extensions\": [\n      {\n        \"name\": \"sample\",\n        \"resolve\": \"extensions/sample\",\n        \"enabled\": true\n      }\n    ]\n  }\n}\n```\n\n> **Warning**\n> Enable/disable the extension requires running the command `npm run build` again.\n\n\n<!-- Skill/Rule: evershop Documentation (packages/evershop/README.md) -->\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</p>\n<p align=\"center\">\n<img width=\"60\" height=\"68\" alt=\"EverShop Logo\" src=\"https://raw.githubusercontent.com/evershopcommerce/evershop/dev/.github/images/logo-green.png\"/>\n</p>\n<p align=\"center\">\n  <h1 align=\"center\">EverShop</h1>\n</p>\n<h4 align=\"center\">\n    <a href=\"https://evershop.io/docs/development/getting-started/introduction\">Documentation</a> |\n    <a href=\"https://demo.evershop.io/\">Demo</a>\n</h4>\n\n<p align=\"center\">\n  <img src=\"https://github.com/evershopcommerce/evershop/actions/workflows/build_test.yml/badge.svg\" alt=\"Github Action\">\n  <a href=\"https://twitter.com/evershopjs\">\n    <img alt=\"Twitter Follow\" src=\"https://img.shields.io/twitter/follow/evershopjs?style=social\">\n  </a>\n  <a href=\"https://discord.gg/GSzt7dt7RM\">\n    <img src=\"https://img.shields.io/discord/757179260417867879?label=discord\" alt=\"Discord\">\n  </a>\n  <a href=\"https://opensource.org/licenses/GPL-3.0\">\n    <img src=\"https://img.shields.io/badge/License-GPLv3-blue.svg\" alt=\"License\">\n  </a>\n</p>\n\n<p align=\"center\">\n<img alt=\"EverShop\" width=\"950\" src=\"https://raw.githubusercontent.com/evershopcommerce/evershop/dev/.github/images/banner.png\"/>\n</p>\n\n## Introduction\n\nEverShop is a modern, TypeScript-first eCommerce platform built with GraphQL and React. Designed for developers, it offers essential commerce features in a modular, fully customizable architecture—perfect for building tailored shopping experiences with confidence and speed.\n\n## Installation Using Docker\n\nYou can get started with EverShop in minutes by using the Docker image. The Docker image is a great way to get started with EverShop without having to worry about installing dependencies or configuring your environment.\n\n```bash\ncurl -sSL https://raw.githubusercontent.com/evershopcommerce/evershop/main/docker-compose.yml > docker-compose.yml\ndocker-compose up -d\n```\n\nFor the full installation guide, please refer to our [Installation guide](https://evershop.io/docs/development/getting-started/installation-guide).\n\n## Documentation\n\n- [Installation guide](https://evershop.io/docs/development/getting-started/installation-guide).\n\n- [Extension development](https://evershop.io/docs/development/module/create-your-first-extension).\n\n- [Theme development](https://evershop.io/docs/development/theme/theme-overview).\n\n## Demo\n\nExplore our demo store.\n\n<p align=\"left\">\n  <a href=\"https://demo.evershop.io/admin\" target=\"_blank\">\n    <img alt=\"evershop-backend-demo\" height=\"35\" alt=\"EverShop Admin Demo\" src=\"https://raw.githubusercontent.com/evershopcommerce/evershop/dev/.github/images/evershop-demo-back.png\"/>\n  </a>\n  <a href=\"https://demo.evershop.io/\" target=\"_blank\">\n    <img alt=\"evershop-store-demo\" height=\"35\" alt=\"EverShop Store Demo\" src=\"https://raw.githubusercontent.com/evershopcommerce/evershop/dev/.github/images/evershop-demo-front.png\"/>\n  </a>\n</p>\n<b>Demo user:</b>\n\nEmail: demo@evershop.io<br/>\nPassword: 123456\n\n## Support\n\nIf you like my work, feel free to:\n\n- ⭐ this repository. It helps.\n- [![Tweet](https://img.shields.io/twitter/url/http/shields.io.svg?style=social)][tweet] about EverShop. Thank you!\n\n[tweet]: https://twitter.com/intent/tweet?url=https%3A%2F%2Fgithub.com%2Fevershopcommerce%2Fevershop&text=Awesome%20React%20Ecommerce%20Project&hashtags=react,ecommerce,expressjs,graphql\n\n## Contributing\n\nEverShop is an open-source project. We are committed to a fully transparent development process and appreciate highly any contributions. Whether you are helping us fix bugs, proposing new features, improving our documentation or spreading the word - we would love to have you as part of the EverShop community.\n\n### Ask a question about EverShop\n\nYou can ask questions, and participate in discussions about EverShop-related topics in the EverShop Discord channel.\n\n<a href=\"https://discord.gg/GSzt7dt7RM\"><img src=\"https://raw.githubusercontent.com/evershopcommerce/evershop/dev/.github/images/discord_banner_github.svg\" /></a>\n\n### Create a bug report\n\nIf you see an error message or run into an issue, please [create bug report](https://github.com/evershopcommerce/evershop/issues/new). This effort is valued and it will help all EverShop users.\n\n### Submit a feature request\n\nIf you have an idea, or you're missing a capability that would make development easier and more robust, please [Submit feature request](https://github.com/evershopcommerce/evershop/issues/new).\n\nIf a similar feature request already exists, don't forget to leave a \"+1\".\nIf you add some more information such as your thoughts and vision about the feature, your comments will be embraced warmly :)\n\nPlease refer to our [Contribution Guidelines](./CONTRIBUTING.md) and [Code of Conduct](./CODE_OF_CONDUCT.md).\n\n## License\n\n[GPL-3.0 License](https://github.com/evershopcommerce/evershop/blob/main/LICENSE)\n\n\n<!-- Skill/Rule: postgres-query-builder Documentation (packages/postgres-query-builder/README.md) -->\n# PostgreSQL query builder for Node\n\nA PostgreSQL query builder for NodeJS.\n\n## Installation\n\n```javascript\nnpm install @evershop/postgres-query-builder\n```\n\n## Usage guide\n\nIt implements async/await.\n\n### Simple select\n\n```javascript\nconst { select } = require('@evershop/postgres-query-builder');\n\nconst products = await select('*')\n  .from('product')\n  .where('product_id', '>', 1)\n  .execute(pool);\n```\n\n### More complex where\n\n```javascript\nconst { select } = require('@evershop/postgres-query-builder');\n\nconst products = await select('*')\n  .from('product')\n  .where('product_id', '>', 1)\n  .and('sku', 'LIKE', 'sku')\n  .execute(pool);\n```\n\n### Event more complex where\n\n```javascript\nconst { select } = require('@evershop/postgres-query-builder');\n\nconst query = select('*').from('product');\nquery.where('product_id', '>', 1).and('sku', 'LIKE', 'sku');\nquery.orWhere('price', '>', 100);\n\nconst products = await query.execute(pool);\n```\n\n### Join table\n\n```javascript\nconst { select } = require('@evershop/postgres-query-builder');\n\nconst query = select('*').from('product');\nquery.leftJoin('price').on('product.`product_id`', '=', 'price.`product_id`');\nquery.where('product_id', '>', 1).and('sku', 'LIKE', 'sku');\nquery.andWhere('price', '>', 100);\n\nconst products = await query.execute(pool);\n```\n\n### Insert&update\n\n<table>\n<tr>\n<th> user_id </th>\n<th> name </th>\n<th> email </th>\n<th> phone </th>\n<th> status </th>\n</tr>\n<tr>\n<td>\n  1\n</td>\n<td>\n  David\n</td>\n<td>\n  emai@email.com\n</td>\n<td>\n  123456\n</td>\n<td>\n  1\n</td>\n</tr>\n</table>\n\n````javascript\n```javascript\nconst {insert} = require('@evershop/postgres-query-builder')\n\nconst query = insert(\"user\")\n.given({name: \"David\", email: \"email@email.com\", \"phone\": \"123456\", status: 1, notExistedColumn: \"This will not be a part of the query\"});\nawait query.execute(pool);\n````\n\n```javascript\nconst { update } = require('@evershop/postgres-query-builder');\n\nconst query = update('user')\n  .given({\n    name: 'David',\n    email: 'email@email.com',\n    phone: '123456',\n    status: 1,\n    notExistedColumn: 'This will not be a part of query'\n  })\n  .where('user_id', '=', 1);\nawait query.execute(pool);\n```\n\n### Working with transaction\n\n```javascript\nconst { Pool } = require('pg');\nconst {\n  insert,\n  getConnection,\n  startTransaction,\n  commit,\n  rollback\n} = require('@evershop/postgres-query-builder');\n\nconst pool = new Pool(connectionSetting);\n\n// Create a connection from the pool\nconst connection = await getConnection(pool);\n\n// Start a transaction\nawait startTransaction(connection);\ntry {\n  await insert('user')\n    .given({\n      name: 'David',\n      email: 'email@email.com',\n      phone: '123456',\n      status: 1,\n      notExistedColumn: 'This will not be a part of the query'\n    })\n    .execute(connection);\n  await commit(connection);\n} catch (e) {\n  await rollback(connection);\n}\n```\n\n## Security\n\nAll user provided data will be escaped.\n\n\n</agent_rules>"}