# Agent Guide For `@orderlyshop/web-components`

Use this package as a headless storefront component library. Prefer native custom elements, light-DOM templates, and normal CSS over framework-specific wrappers unless the user asks for a framework integration.

## Agent Operating Contract

- These instructions are optimized for GPT-5.5-class coding agents and other modern LLMs. Work from the user's requested storefront outcome, choose the package-owned component or CLI that owns that outcome, and keep edits scoped to that path.
- Prefer package configuration, typed properties, declarative templates, semantic tokens, and package CLI tools over copying component internals into a shop.
- Do not infer attribute names, event names, template slots, or CSS hooks from memory. Use the docs and metadata in this package as the source of truth.
- Stop only when the behavior is implemented, verified with the nearest relevant script, and visually inspected in a browser when available. If validation needs data, account ids, credentials, a browser, or a running backend, report the exact missing prerequisite.

## Required Reading and Intake

- Read `README.md`, `DESIGN.md`, `docs/shop-best-practices.md`, `docs/components/README.md`, then `custom-elements.json` or `html-custom-data.json` before shop-specific edits. Read `docs/components/product-rail.md` and `docs/components/product-grid.md` before product listing work.
- Use `docs/shop-best-practices.md` as the completion checklist for branded shop work. A finished shop must not look like the default scaffold with minor token changes.
- For new shops, run `npx orderly-init-shop` first. Ask for the Orderly account id, legal webshop owner name, legal owner CVR, and a reference website URL; if no reference exists, ask for a short style description.
- Set `defaultShop.legalOwnerName` and `defaultShop.legalOwnerCvr`. `orderly-page-layout` renders the required ownership notice after footer content, and shop templates must not replace it.
- Use the account id for tenant-scoped `src/shop-query.ts`. Use the reference, catalog inspection, and online research as design direction for `src/style.css`; never copy proprietary assets, text, logos, or brand marks without user confirmation.
- Build the first version around catalog-driven content: homepage sections, category introductions, product context, useful navigation, and a visual system based on `DESIGN.md` tokens plus scoped CSS.
- Aim for current premium frontend craft: responsive art direction, strong imagery, clear interaction states, appropriate motion, performance, and accessibility.
- Before reporting completion, run the local dev/build command and visually inspect homepage, category, product, basket, and checkout on desktop and mobile when a browser is available.

## Query Rules

- Use `configureShop({ defaultShop: { defaultQuery } })` for shop-wide query scope. `defaultQuery` is a full Core `SearchQuery`.
- Do not create package-specific account id shortcuts. Tenant scoping is just `SearchQuery.SourceAccountId`.
- Read `docs/search-syntax.md` before writing category or rail queries. Whitespace in `SearchQuery.Query` is narrowing; use `|` for OR alternatives such as `lego | matchbox | playmobil`. Multiple `SearchQuery.Tags` are narrowing AND-style filters, not broad alternatives.
- For simple markup-driven searches, use declarative query attributes:
  - `keywords` maps to `SearchQuery.Query`.
  - `tags` maps to `SearchQuery.Tags`.
  - `hidden-query` maps to `SearchQuery.HiddenQuery`.
  - `order-by` maps to `SearchQuery.OrderBy`.
  - `store-id` maps to `SearchQuery.StoreId`.
  - `featured` maps to `SearchQuery.Featured`.
- The same query values can be grouped inside a child `<query>` element.
- Use typed JavaScript properties for full Core contracts:
  - `query: SearchQuery`
  - `defaultQuery: SearchQuery`
  - `client: OrderlyClient`
  - `basketController: BasketController`
- In vanilla browser scripts, use `OrderlyWebComponents.createSearchQuery({ query, tags, orderBy })` from the standalone bundle when you need a SearchQuery without importing protobuf helpers.

## Implementation Defaults

- Keep components headless. Prefer configuration, typed properties, templates, slots, semantic tokens, and scoped shop CSS over copying package internals.
- Start theme work from `DESIGN.md`. Visual differentiation is part of the first implementation, not later polish.
- Add shop-owned editorial sections around package components. Preserve package-owned product tiles, checkout, product detail behavior, image viewers, structured data, accessibility, and generated URLs unless the user explicitly asks for a different structure.
- Built-in UI copy defaults to Danish. Use `configureShop({ uiLanguage: "EN" })` for English shops, and prefer shop attributes/templates for wording that is unique to one storefront.
- Preserve `data-orderly-template`, `data-orderly-bind`, `data-orderly-slot`, and `data-orderly-action`. Put shared templates in a document-level registry using `data-orderly-for`.
- Keep browser code free of Node HTTP modules. Do not store tokens, API keys, OAuth responses, cookie values, or other secrets.
- Use `configureShop({ consent })` before enabling optional analytics, marketing, personalization, or shop-owned cookies. Use `setOrderlyCookie()` or `hasCookieConsent()` for optional browser state.
- Treat localStorage basket and checkout profile data as user-owned state.
- Product images should default to `fit="contain"`, white background, and square aspect ratio in product tiles.
- Use `orderly-stored-image` for package/product images when possible and set the appropriate `image-role` (`product-tile`, `product-detail`, `thumbnail`, `basket-line`, `checkout-line`, or `fullsize`) so image URLs reuse configured CDN dimensions.
- Product grids should support continuation-token based dynamic paging without requiring a visible load-more button.
- Use `orderly-home-page` for default storefront homepages instead of generating product rails in app code. Use its `hero` slot/template for a custom homepage hero before replacing the full layout. Set `basket-mode="inline-desktop"` when the design needs a package-owned desktop basket rail instead of custom portal glue.
- Use `orderly-category-page` for category routes. Default category links should use `/categories/<category-path>/` so builds can generate and hydrate server-rendered category pages. Use `/category.html#id=<encoded-category-path-or-slug>` only for shops that explicitly opt into hash routing. Prefer navigation `heroImage`, `heroLayout: "covers"`, `heroCoverCount`, and category `description` before replacing the category hero template.
- Keep `orderly-navigation` sticky by default. Use `sticky="false"` only when a shop intentionally wants navigation to scroll away. Use `persist-state state-key="main-menu"` for vertical desktop menus that should remember open branches, and use `slot="menu-before"`/`slot="menu-after"` for store finder, campaign, volunteer, or other menu promo links.
- Use package-owned basket and checkout surfaces first: `<orderly-basket-icon href="/checkout.html" placement="mobile-fixed" hide-when-empty>`, `basket-mode="inline-desktop"`, and `orderly-checkout-page`.
- Use `orderly-product-detail-page` for full product routes. Set `share-url` to the product `SearchObject.ShareURL.URL`; the component loads the product through `SearchQuery.ShareUrl`.
- Keep category page generation in the normal shop build. Use `orderly-build-category-pages` without `--no-hydrate` so homepage/category pages get initial HTML for SEO and less visible loading shift. Pass `--base-url` or set `VITE_ORDERLY_BASE_URL` to override the default `https://service.orderly.shop` snapshot backend. Treat warnings about category pages or homepage rails matching 0 products as blockers; use `--strict-empty-categories` in CI when empty categories should fail the build.
- For real product URLs on traditional hosting, use the package-owned helpers in `server/`: Apache `.htaccess`, Nginx rewrite config, PHP product renderer, and optional Node product snapshot endpoint. Do not copy this logic into example-shop.
- Use `navigation.ts` for category/navigation structure. Run `npx orderly-init-navigation --suggest --account-id <account-id>` when sampling helps, then read `querySyntax` and `navigationSuggestions` in `navigation-products.json` before exporting `navigationDefinitions: NavigationDefinition[]` with stable unique slugs, at most two levels, optional hero/content fields, and plain `SearchQueryInput` values such as `query: { query: "sko | sneakers" }` or `query: { query: "kjole | sommerkjole", tags: ["dametøj"] }`.

## Common Patterns

Declarative product rail:

```html
<orderly-product-rail
  title="Sko"
  cta-label="Se alle"
  cta-href="/categories/sko/"
  keywords="sneakers | støvler | sandaler"
  tags="sko">
</orderly-product-rail>
```

Structured query markup:

```html
<orderly-product-rail title="Sko">
  <query>
    <tags>sko</tags>
    <keywords>sneakers | støvler | sandaler</keywords>
    <order-by>CreatedTime desc</order-by>
  </query>
</orderly-product-rail>
```

Typed query setup:

```ts
import { create } from "@bufbuild/protobuf";
import { SearchQuerySchema } from "@orderlyshop/core-client";

productRail.query = create(SearchQuerySchema, {
  Query: "sneakers | støvler | sandaler",
  OrderBy: ["CreatedTime desc"]
});
```

Standalone browser setup:

```html
<script src="/node_modules/@orderlyshop/web-components/dist/browser/orderly-web-components.global.js"></script>
<script>
  const { configureShop } = OrderlyWebComponents;
  configureShop({
    uiLanguage: "DA",
    defaultShop: {
      navigationDefinitions: [
        { label: "Sko", slug: "sko", query: { query: "sko | sneakers" } }
      ]
    }
  });
</script>
```
