Skip to content

Latest commit

 

History

History
175 lines (133 loc) · 12 KB

File metadata and controls

175 lines (133 loc) · 12 KB

AGENTS.md — search-resolver

Repository Purpose

vtex.search-resolver is a VTEX IO backend service (builder node) that implements the GraphQL resolvers for the catalog, search, and orders schema published by vtex.search-graphql.

It is the resolver layer of the Intelligent Search stack. The GraphQL schema (the contract) lives in vtex.search-graphql; this app loads that schema at runtime via the dependency vtex.search-graphql/graphql and registers its resolvers + directives against it (see node/index.ts).

Where it sits in the IS topology

App Role
vtex.search-graphql App-owned GraphQL schema (the contract)
vtex.search-resolver (this repo) GraphQL resolvers for that schema
vtex.intelligent-search-api Backend HTTP wrapper around the IS platform service
vtex.search-result Store Framework PLP consuming the GraphQL surface
vtex.delivery-promise-components Storefront blocks consuming catalog_count + pickup endpoints
vtex.search-session Owns the search session namespace that feeds segment/facets

Sources of Truth

File What it defines
manifest.json App identity (vtex.search-resolver@1.102.2), builders (node, docs), dependencies (vtex.messages, vtex.catalog-api-proxy, vtex.search-graphql, vtex.rewriter, vtex.sae-analytics, vtex.intelligent-search-api), settingsSchema (slugifyLinks, shouldUseNewPDPEndpoint, shouldUseNewPLPEndpoint), policies (vtex.messages:translate-messages, vtex.catalog-api-proxy:catalog-proxy/authenticated-catalog-proxy, …)
node/service.json Runtime: nodejs stack, 2048MB memory, 80 shared CPU @ 95%, ttl 30s, timeout 12s, 30–250 replicas, 2 workers. No routes — this service is a pure GraphQL plugin mounted by vtex.search-graphql via the schema.
node/index.ts Service composition, LRU caches (segmentCache: 1000, searchCache: 3000, messagesCache: 3000, vbaseCache: 3000, appsCache: 1500, intschCache: 3000), per-client timeouts (default 3s, search: 6s, intelligentSearchApi: 9s), metrics.trackCache instrumentation. Imports schema from vtex.search-graphql/graphql.
node/resolvers/index.ts Composes searchFieldResolvers, benefitsFieldResolvers, searchQueries, statsQueries. This is the resolver entry point.
node/resolvers/search/ All catalog / search / autocomplete / product / brand / category / facets resolvers + tests (product.test.ts, productPriceRange.test.ts, assemblyOption.test.ts, newURLs.test.ts, index.test.ts)
node/resolvers/benefits/, node/resolvers/stats/ Smaller resolver groups
node/directives/ Schema directives (@cacheControl, @withSegment, etc.) registered via schemaDirectives in node/index.ts
node/clients/index.ts Composes clients: search, checkout, rewriter, intelligentSearchApi, intsch
node/clients/intelligent-search-api.ts ExternalClient against the vtex.intelligent-search-api IO app (note: NOT the IS platform service directly)
node/clients/intsch/ Direct client to the IS platform backend (lower-level than intelligentSearchApi)
node/clients/search.ts Legacy VTEX search backend (still used while the new IS endpoints are gated by settings)
node/featureFlags.ts In-code feature toggles (currently VTEX_ASSETS_URL: true)
node/commons/, node/services/, node/utils/ Shared helpers (caching keys, slug builders, query parsing, search state)
node/typings/ Platform typings — regenerated by Toolbelt; do not hand-edit
node/jest.config.js Jest 29 + ts-jest, coverageProvider: 'v8', `testRegex: '(.*(test
node/mocks/, node/__mocks__/ Test fixtures shared across resolver tests
policies.json Per-account policy declarations (parallel to manifest.json policies)
dangerfile.js Danger rules for PR review
.vtex/deployment.yaml, .vtex/catalog-info.yaml DK CI deployment definition (techdocs-v1 pipeline) + Backstage entity (referenceId: 6PIM3PYV)
CHANGELOG.md Per-release changelog

Architecture

The service is a pure GraphQL plugin: node/index.ts exports new Service({...}) with no custom HTTP routes. vtex.search-graphql (declared as a dependency) provides the schema at vtex.search-graphql/graphql. At runtime, the IO platform composes the schema + the resolvers exported here.

GraphQL request ─► vtex.graphql-server / @vtex/api Service runtime
                    └─► schema (imported from vtex.search-graphql)
                         └─► resolvers (composed in node/resolvers/index.ts)
                              ├─ Query.product / facets / autocomplete / topSearches / …
                              ├─ field resolvers on Product, SKU, Brand, Category, Offer, AssemblyOption, …
                              ├─ benefits field resolvers (promotions, discount lists)
                              └─ schemaDirectives (@cacheControl, @withSegment, …)
                                   └─► clients.{search, intelligentSearchApi, intsch, checkout, rewriter}

Resolver organization

Directory Purpose
node/resolvers/search/ Catalog + search core. Sub-modules:
product.ts, brand.ts, category.ts — entity resolvers
autocomplete.ts, productPriceRange.ts, offer.ts, discount.ts — composed fields
assemblyOption.ts, itemMetadata*.ts — product configuration
newURLs.ts — URL/slug normalization
modules/ — internal helpers
node/resolvers/benefits/ Promotions, discount lists, badges
node/resolvers/stats/ Top-searches and analytics queries
node/directives/ Schema directive implementations

Endpoint switching

Three settings control the new-vs-legacy migration:

Setting Default Effect
slugifyLinks false When true, links use slugify instead of the default catalog slug
shouldUseNewPDPEndpoint false When true, PDP queries hit the new IS endpoint via intelligentSearchApi / intsch; otherwise the legacy search client
shouldUseNewPLPEndpoint false Same for PLP

These are per-account app settings, not FeatureHub flags. Toggling them changes which client takes the hot path.

Caches and timeouts

Configured in node/index.ts:

Client Cache Capacity Timeout Notes
search (legacy) searchCache 3000 6000ms concurrency: 10
intelligentSearchApi (IS via IO app) 9000ms retries: 0, concurrency: 10
intsch (direct IS) intschCache 3000
messagesGraphQL messagesCache 3000 2000ms concurrency: 10
segment segmentCache 1000 3000ms small + immutable
vbase vbaseCache 3000 default
apps appsCache 1500 2000ms retries: 2, concurrency: 5
default 3000ms retries: 2

metrics.trackCache(<name>, <cache>) exposes hit/miss to platform observability.

External APIs (outbound policies)

From manifest.json policies:

Policy Purpose
vtex.messages:translate-messages i18n via vtex.messages
vtex.catalog-api-proxy:catalog-proxy Catalog reads through the official proxy
vtex.catalog-api-proxy:authenticated-catalog-proxy Authenticated catalog reads
(transitively via deps) vtex.intelligent-search-api, vtex.rewriter, vtex.sae-analytics IS, URL resolution, analytics

CI

.github/workflows/pull-request.yml runs three jobs on PR:

  1. io-app-testvtex/action-io-app-test runs builder-aware Jest in each builder directory.
  2. lintvtex/action-lint runs the linter (root yarn lintcd node && yarn linttsc --noEmit).
  3. Cypressvtex/action-io-app-cypress@v1 runs the vtex/search-tests suite against the biggy account, 4 containers, parallel. Requires repository secrets APP_KEY, APP_TOKEN, RECORD_KEY.

Verified Commands

make dev          # yarn install (root + node) + vtex setup
make lint         # cd node && yarn lint (tsc --noEmit — type-check)
make test         # cd node && yarn test (jest 29 + ts-jest)
make coverage     # cd node && yarn test --coverage (60% threshold)
make check        # lint + test (matches root `yarn verify`)
make link         # vtex link (uses active VTEX account/workspace)
make run          # alias for make link

Root yarn scripts: yarn lint, yarn format, yarn test, yarn verify (lint + test).

Expected Skills

  • vtex-io-cli · vtex-io-app-structure · vtex-io-service-apps · vtex-io-graphql-api
  • specification + implementing (vtex-agent-skills) for the SDD Lite workflow
  • For SDD Full work, use the spec-kit pipeline against the parent Specs repo (is-io-specs/.specify/)

Expected MCPs

  • GitHub MCP — cross-repo references (especially vtex.search-graphql for schema changes, vtex.intelligent-search-api for backend, vtex/search-tests for Cypress), issues, PRs.
  • Atlassian MCP — Jira/Confluence context.

Multi-repo Specs

Part of the is-io-specs multi-repo workspace. SpecKit artifacts (.specify/memory/constitution.md, docs/scope_of_work/, specs/<feature>/) live at the parent aggregator. This repo intentionally has no local .specify/. See the Multi-repo spec-kit extension.

Autonomy Limits

Toolbelt and platform

  • Never run vtex link, vtex publish, vtex deploy, workspace promotion, or any account/workspace-changing Toolbelt command without explicit confirmation.
  • Never modify manifest.json version directly — use vtex release <patch|minor|major> stable.
  • Never modify node/typings/ — regenerated by vtex setup --typings --ignore-linked.
  • Ask before adding/removing builders or policies in manifest.json.

Schema contract

  • The schema is owned by vtex.search-graphql, not this repo. Adding a new field requires a coordinated PR there first. Resolver additions here will fail at runtime if the field is not in the schema.
  • Do not change field shapes of Product, SKU, Brand, Category, Facet, Offer, AssemblyOption without coordinated PRs in vtex.search-result (PLP) and any private storefront consumers.
  • Schema directives (@cacheControl, @withSegment) are part of the contract. Removing or changing semantics affects caching and segment isolation.

Resolver constraints

  • Cache headers are emitted via the @cacheControl directive on schema fields, not from resolver code. If you need a non-standard TTL, change the schema in vtex.search-graphql, not the resolver.
  • Segment isolation: @withSegment ensures the resolver sees the shopper's segment context. Do not bypass it for fields that vary per-shopper.
  • @gocommerce/utils branches behavior for go-commerce stores. Always go through the existing helpers; do not gate by account name.

Endpoint switching

  • shouldUseNewPDPEndpoint / shouldUseNewPLPEndpoint are per-account flags. Adding a new flag requires updating manifest.json:settingsSchema and the corresponding read sites.
  • Never call intelligentSearchApi and the legacy search client for the same field — pick one based on settings, or you'll double-bill and double-cache.

Observability

  • Log via ctx.vtex.logger with structured payloads. ctx.vtex.logger.info({ message, ... }), not bare strings.
  • Coverage is collected by Jest (coverageProvider: 'v8') into node/coverage/. The directory is gitignored; SonarQube ingestion is wired via DK CI.

Cypress autonomy

  • The Cypress job runs against the biggy account. Never point it at a real customer account without explicit coordination — Cypress runs may issue real cart/order operations.
  • Repository secrets APP_KEY, APP_TOKEN, RECORD_KEY must be set in GitHub before the Cypress job will work in a forked PR.