Business Rules Assessment

myowjaYOY/commerce

Generated by DocAgent — automated codebase documentation analysis. Based on analysis of 3 screens. Subject matter expert review is recommended before distribution.

April 19, 2026

Business Rules Assessment

commerce

Generated by DocAgent — automated codebase documentation analysis. Based on analysis of 5 screens. Subject matter expert review is recommended before distribution.

April 20, 2026

Commerce Application

Business Rules Assessment

April 2026


1. Overview

Scope. This Business Rules Assessment documents all business rules, validations, calculations, and conditional logic observable from the implemented screen documentation for the Commerce application. Rules are extracted from five screens: Home (/), Item Detail (/[page]), Product Detail (/product/[handle]), Search (/search), and Search Detail (/search/[collection]). Rules embedded in child components whose source code was not provided (e.g., ProductDescription, Gallery, Carousel, ThreeItemGrid, Footer, ProductGridItems) are outside the scope of this document, as are rules governing checkout, cart, account management, and any other routes not listed above.

Methodology. Rules are reverse-engineered from technical screen documentation written for developers. Each rule is expressed declaratively per SBVR principles — stating what must be true rather than how the code implements it. Rules are classified using BABOK v3.0 categories (Structural, Operative, Decision), structured using DMN v1.5 conventions for decision tables, and governed per Business Rules Manifesto v2.0 principles of rule independence. Enforcement points (Client, Server, Both) are assigned based on where the rule logic is described as executing in the documentation.

Limitations. This document is derived entirely from per-screen technical documentation, not from requirements documents, policy manuals, or stakeholder interviews. Business rationale is stated only where the documentation explicitly provides it; all other rationale is marked as not documented or formally inferred. Rules implemented within undocumented child components cannot be cataloged here. Because all five documented screens are React Server Components with no client-side state, the majority of rules are enforced server-side. This document reflects a partial view of the application — rules from screens not included in the assessed documentation are outside scope.

Coverage. This Business Rules Assessment covers 5 screens of the Commerce application:

Business rules derived from screens not included in the assessed documentation are outside the scope of this document.

How to use this document. Use the Rule Inventory for quick lookup by domain, category, or criticality. Use the Business Rules Catalog for full rule details including conditions, validation logic, and testing implications. Use the Decision Tables for multi-condition conditional logic. Use the Gap Analysis to identify risks, missing rules, and items requiring stakeholder verification.

Disclosure. Generated by DocAgent — automated codebase documentation analysis. Subject matter expert review is recommended before distribution.


2. Rule Inventory

# Rule Name Domain Category Enforcement Criticality Screen(s)
BR-001 Public Page Requires No Authentication Content Visibility & Access Control Structural Server Low Home (/), Item Detail (/[page]), Product Detail (/product/[handle]), Search (/search), Search Detail (/search/[collection])
BR-002 Invalid Page Handle Returns 404 Content Visibility & Access Control Operative Server High Item Detail (/[page])
BR-003 Invalid Product Handle Returns 404 Content Visibility & Access Control Operative Server High Product Detail (/product/[handle])
BR-004 Invalid Collection Slug Returns 404 Content Visibility & Access Control Operative Server High Search Detail (/search/[collection])
BR-005 Hidden Product Excluded from Search Indexing Content Visibility & Access Control Operative Server Medium Product Detail (/product/[handle])
BR-006 Hidden Product Remains Directly Accessible Content Visibility & Access Control Structural Server Medium Product Detail (/product/[handle])
BR-007 Product Image Gallery Capped at Five Images Product Display Structural Server Low Product Detail (/product/[handle])
BR-008 Related Products Section Suppressed When Empty Product Display Operative Server Low Product Detail (/product/[handle])
BR-009 Product Availability Expressed in Structured Data Product Data Integrity Decision Server Medium Product Detail (/product/[handle])
BR-010 Product Price Range Expressed as Aggregate Offer Product Data Integrity Structural Server Low Product Detail (/product/[handle])
BR-011 Item Detail SEO Title Fallback Chain SEO & Metadata Decision Server Medium Item Detail (/[page])
BR-012 Item Detail SEO Description Fallback Chain SEO & Metadata Decision Server Medium Item Detail (/[page])
BR-013 Item Detail Classified as OpenGraph Article SEO & Metadata Structural Server Low Item Detail (/[page])
BR-014 Item Detail OpenGraph Timestamps from Shopify Dates SEO & Metadata Structural Server Low Item Detail (/[page])
BR-015 Product Detail SEO Title Fallback Chain SEO & Metadata Decision Server Medium Product Detail (/product/[handle])
BR-016 Product Detail SEO Description Fallback Chain SEO & Metadata Decision Server Medium Product Detail (/product/[handle])
BR-017 Product OpenGraph Image Conditionally Included SEO & Metadata Decision Server Low Product Detail (/product/[handle])
BR-018 Collection SEO Title Fallback Chain SEO & Metadata Decision Server Medium Search Detail (/search/[collection])
BR-019 Collection SEO Description Fallback Chain SEO & Metadata Decision Server Medium Search Detail (/search/[collection])
BR-020 Home Page Classified as OpenGraph Website SEO & Metadata Structural Server Low Home (/)
BR-021 Sort Parameter Resolved with Default Fallback Search & Filtering Decision Server Medium Search (/search), Search Detail (/search/[collection])
BR-022 Search Results Summary Shown Only with Query Search & Filtering Operative Server Low Search (/search)
BR-023 Zero Search Results Displays No-Results Message Search & Filtering Operative Server Medium Search (/search)
BR-024 Product Grid Suppressed When No Products Search & Filtering Operative Server Low Search (/search)
BR-025 Results Count Text Grammatically Pluralized Search & Filtering Decision Server Low Search (/search)
BR-026 Empty Collection Displays No-Products Message Collection Browsing Operative Server Medium Search Detail (/search/[collection])
BR-027 Last Updated Date Formatted with Runtime Locale Product Data Integrity Structural Server Low Item Detail (/[page])
BR-028 Related Product Links Prefetched on Viewport Entry Product Display Operative Client Low Product Detail (/product/[handle])

3. Business Rules Catalog

3.1: Content Visibility & Access Control

Description: Rules governing which pages are publicly accessible, which URL handles produce a 404 response, and how product visibility is controlled for search engine indexing.

Screens involved: Home (/), Item Detail (/[page]), Product Detail (/product/[handle]), Search (/search), Search Detail (/search/[collection])


BR-001: Public Page Requires No Authentication

Domain: Content Visibility & Access Control Category: Structural Enforcement: Server Criticality: Low

Rule Statement: All five documented screens must be accessible to any visitor without authentication or role-based authorization.

Conditions: Not applicable — this is an unconditional structural constraint.

Validation Details:

Source Evidence: Home (/) §2, Item Detail (/[page]) §2, Product Detail (/product/[handle]) §2, Search (/search) §2, Search Detail (/search/[collection]) §2

Business Rationale: Public storefront pages must be accessible to all potential customers without requiring account creation or login, maximizing reach and enabling search engine crawling.

Related Rules: BR-002, BR-003, BR-004, BR-005

Testing Implications:


BR-002: Invalid Page Handle Returns 404

Domain: Content Visibility & Access Control Category: Operative Enforcement: Server Criticality: High

Rule Statement: If a requested Shopify page handle does not resolve to an existing page, the application must return a 404 Not Found response rather than rendering an empty or broken page.

Conditions:

Validation Details:

Source Evidence: Item Detail (/[page]) §8, §4, §9

Business Rationale: Prevents arbitrary URL segments from producing rendered pages with empty or undefined content, maintaining content integrity and a consistent user experience for broken links.

Related Rules: BR-001

Testing Implications:


BR-003: Invalid Product Handle Returns 404

Domain: Content Visibility & Access Control Category: Operative Enforcement: Server Criticality: High

Rule Statement: If a requested Shopify product handle does not resolve to an existing product, the application must return a 404 Not Found response.

Conditions:

Validation Details:

Source Evidence: Product Detail (/product/[handle]) §4, §8, §9, §10

Business Rationale: Prevents broken product URLs from rendering empty pages, ensuring consistent 404 behavior for invalid or removed product handles.

Related Rules: BR-001, BR-005

Testing Implications:


BR-004: Invalid Collection Slug Returns 404

Domain: Content Visibility & Access Control Category: Operative Enforcement: Server Criticality: High

Rule Statement: If a requested collection slug does not resolve to an existing Shopify collection, the application must return a 404 Not Found response.

Conditions:

Validation Details:

Source Evidence: Search Detail (/search/[collection]) §2, §5, §8, §10

Business Rationale: Ensures that only valid, existing Shopify collections can be viewed, preventing broken or empty collection pages from being served.

Related Rules: BR-001, BR-026

Testing Implications:


BR-005: Hidden Product Excluded from Search Indexing

Domain: Content Visibility & Access Control Category: Operative Enforcement: Server Criticality: Medium

Rule Statement: If a product is tagged with HIDDEN_PRODUCT_TAG, the product detail page must be marked noindex, nofollow in its metadata, preventing search engine indexing and link following.

Conditions:

Validation Details:

Source Evidence: Product Detail (/product/[handle]) §2, §8, §14

Business Rationale: Not stated in documentation — verify with business stakeholders. [Not documented — WHO: Product owner or merchandising team; WHAT: What is the business purpose of the HIDDEN_PRODUCT_TAG mechanism — e.g., staging products, discontinued items, internal SKUs?; WHERE: Insert in the Business Rationale field of BR-005]

Related Rules: BR-006, BR-003

Testing Implications:


BR-006: Hidden Product Remains Directly Accessible

Domain: Content Visibility & Access Control Category: Structural Enforcement: Server Criticality: Medium

Rule Statement: A product tagged with HIDDEN_PRODUCT_TAG must remain accessible via its direct URL; the tag must not prevent page rendering or trigger a 404 response.

Conditions: Not applicable — this is an unconditional structural constraint for tagged products.

Validation Details:

Source Evidence: Product Detail (/product/[handle]) §2, §8, §14

Business Rationale: Not stated in documentation — verify with business stakeholders. [Not documented — WHO: Product owner; WHAT: Is it intentional that hidden products are fully accessible via direct URL, or should they also be access-controlled?; WHERE: Insert in the Business Rationale field of BR-006]

Related Rules: BR-005

Testing Implications:


3.2: Product Data Integrity

Description: Rules governing the accuracy and completeness of product data as presented to users and search engines, including availability signaling, price representation, and date formatting.

Screens involved: Item Detail (/[page]), Product Detail (/product/[handle])


BR-009: Product Availability Expressed in Structured Data

Domain: Product Data Integrity Category: Decision Enforcement: Server Criticality: Medium

Rule Statement: The JSON-LD structured data for a product must express availability as https://schema.org/InStock when the product is available for sale, and https://schema.org/OutOfStock otherwise.

Conditions:

Validation Details:

Source Evidence: Product Detail (/product/[handle]) §8

Business Rationale: Communicates stock status to search engines via structured data, enabling accurate rich result display (e.g., "In Stock" badges in Google Shopping).

Related Rules: BR-010

Testing Implications:


BR-010: Product Price Range Expressed as Aggregate Offer

Domain: Product Data Integrity Category: Structural Enforcement: Server Criticality: Low

Rule Statement: The JSON-LD structured data for a product must represent pricing using the AggregateOffer type, specifying both highPrice from priceRange.maxVariantPrice.amount and lowPrice from priceRange.minVariantPrice.amount.

Conditions: Not applicable — this is an unconditional structural constraint applied to all product detail pages.

Validation Details:

Source Evidence: Product Detail (/product/[handle]) §8

Business Rationale: Accurately represents products with multiple variant price points to search engines, enabling correct price range display in rich results.

Related Rules: BR-009

Testing Implications:


BR-027: Last Updated Date Formatted with Runtime Locale

Domain: Product Data Integrity Category: Structural Enforcement: Server Criticality: Low

Rule Statement: The "last updated" date displayed on an Item Detail page must be formatted using the server runtime's default locale with year: "numeric", month: "long", and day: "numeric" options.

Conditions: Not applicable — this formatting is applied unconditionally to page.updatedAt.

Validation Details:

Source Evidence: Item Detail (/[page]) §3, §4, §8, §10

Business Rationale: Not stated in documentation — verify with business stakeholders. [Not documented — WHO: Product owner; WHAT: Should the date be formatted in the user's browser locale rather than the server locale? Is the current server-locale behavior intentional?; WHERE: Insert in the Business Rationale field of BR-027 and note in GAP-04]

Related Rules: None

Testing Implications:


3.3: SEO & Metadata

Description: Rules governing the generation of <head> metadata, Open Graph tags, robots directives, and JSON-LD structured data across all documented screens.

Screens involved: Home (/), Item Detail (/[page]), Product Detail (/product/[handle]), Search Detail (/search/[collection])


BR-011: Item Detail SEO Title Fallback Chain

Domain: SEO & Metadata Category: Decision Enforcement: Server Criticality: Medium

Rule Statement: The SEO title for an Item Detail page must use page.seo.title if present; otherwise it must fall back to page.title.

Conditions:

Validation Details:

Source Evidence: Item Detail (/[page]) §8

Business Rationale: Ensures that pages without explicit SEO overrides in Shopify still produce meaningful metadata, while allowing merchants to customize SEO titles independently of display titles.

Related Rules: BR-012

Testing Implications:


BR-012: Item Detail SEO Description Fallback Chain

Domain: SEO & Metadata Category: Decision Enforcement: Server Criticality: Medium

Rule Statement: The SEO description for an Item Detail page must use page.seo.description if present; otherwise it must fall back to page.bodySummary.

Conditions:

Validation Details:

Source Evidence: Item Detail (/[page]) §8

Business Rationale: Ensures that pages without explicit SEO descriptions still produce meaningful metadata using the page body summary, while allowing merchant SEO overrides.

Related Rules: BR-011

Testing Implications:


BR-013: Item Detail Classified as OpenGraph Article

Domain: SEO & Metadata Category: Structural Enforcement: Server Criticality: Low

Rule Statement: All Item Detail pages must set openGraph.type to "article" in their metadata.

Conditions: Not applicable — this is applied unconditionally to all /[page] routes.

Validation Details:

Source Evidence: Item Detail (/[page]) §8

Business Rationale: Classifies all Shopify CMS pages as article-type content for social sharing and SEO purposes, enabling article-specific rich previews on social platforms.

Related Rules: BR-014, BR-020

Testing Implications:


BR-014: Item Detail OpenGraph Timestamps from Shopify Dates

Domain: SEO & Metadata Category: Structural Enforcement: Server Criticality: Low

Rule Statement: Item Detail page metadata must populate openGraph.publishedTime from page.createdAt and openGraph.modifiedTime from page.updatedAt.

Conditions: Not applicable — applied unconditionally when the page object is valid.

Validation Details:

Source Evidence: Item Detail (/[page]) §8

Business Rationale: Provides social platforms and search engines with accurate publication and modification timestamps for article-type content, supporting freshness signals in search ranking.

Related Rules: BR-013, BR-027

Testing Implications:


BR-015: Product Detail SEO Title Fallback Chain

Domain: SEO & Metadata Category: Decision Enforcement: Server Criticality: Medium

Rule Statement: The SEO title for a Product Detail page must use product.seo.title if present; otherwise it must fall back to product.title.

Conditions:

Validation Details:

Source Evidence: Product Detail (/product/[handle]) §8

Business Rationale: Allows merchants to set SEO-specific titles distinct from display titles, while ensuring all products have meaningful metadata even without explicit SEO configuration.

Related Rules: BR-016, BR-011

Testing Implications:


BR-016: Product Detail SEO Description Fallback Chain

Domain: SEO & Metadata Category: Decision Enforcement: Server Criticality: Medium

Rule Statement: The SEO description for a Product Detail page must use product.seo.description if present; otherwise it must fall back to product.description.

Conditions:

Validation Details:

Source Evidence: Product Detail (/product/[handle]) §8

Business Rationale: Allows merchants to set SEO-specific descriptions, while ensuring all products have meaningful metadata using the product description as a fallback.

Related Rules: BR-015, BR-012

Testing Implications:


BR-017: Product OpenGraph Image Conditionally Included

Domain: SEO & Metadata Category: Decision Enforcement: Server Criticality: Low

Rule Statement: The OpenGraph image metadata for a Product Detail page must only be included if product.featuredImage.url is truthy; if absent, the OpenGraph images array must be omitted or set to null.

Conditions:

Validation Details:

Source Evidence: Product Detail (/product/[handle]) §8, §10

Business Rationale: Prevents broken or empty og:image tags from being emitted for products without a featured image, which could degrade social sharing previews.

Related Rules: BR-015, BR-016

Testing Implications:


BR-018: Collection SEO Title Fallback Chain

Domain: SEO & Metadata Category: Decision Enforcement: Server Criticality: Medium

Rule Statement: The SEO title for a Search Detail page must use collection.seo.title if present; otherwise it must fall back to collection.title.

Conditions:

Validation Details:

Source Evidence: Search Detail (/search/[collection]) §8

Business Rationale: Allows merchants to set SEO-specific collection titles, while ensuring all collection pages have meaningful metadata using the collection display title as a fallback.

Related Rules: BR-019, BR-011, BR-015

Testing Implications:


BR-019: Collection SEO Description Fallback Chain

Domain: SEO & Metadata Category: Decision Enforcement: Server Criticality: Medium

Rule Statement: The SEO description for a Search Detail page must use collection.seo.description if present; if absent, it must fall back to collection.description; if that is also absent, it must fall back to the generated string "${collection.title} products".

Conditions:

Validation Details:

Source Evidence: Search Detail (/search/[collection]) §8

Business Rationale: Ensures all collection pages have a meaningful SEO description even when merchants have not configured explicit SEO fields, using a generated description as a last resort.

Related Rules: BR-018, BR-012

Testing Implications:


BR-020: Home Page Classified as OpenGraph Website

Domain: SEO & Metadata Category: Structural Enforcement: Server Criticality: Low

Rule Statement: The Home page must set openGraph.type to "website" in its metadata.

Conditions: Not applicable — this is applied unconditionally to the / route.

Validation Details:

Source Evidence: Home (/) §13

Business Rationale: Identifies the home page as a generic website page for social sharing platforms, as opposed to article, product, or other content-specific types.

Related Rules: BR-013

Testing Implications:


3.4: Search & Filtering

Description: Rules governing the display of search results, sort parameter resolution, results summary messaging, and product grid visibility on the Search screen.

Screens involved: Search (/search), Search Detail (/search/[collection])


BR-021: Sort Parameter Resolved with Default Fallback

Domain: Search & Filtering Category: Decision Enforcement: Server Criticality: Medium

Rule Statement: The sort URL query parameter must be resolved to a valid { sortKey, reverse } pair by matching against the sorting constants array; if no match is found, defaultSort must be used.

Conditions:

Validation Details:

Source Evidence: Search (/search) §4, §7, §8; Search Detail (/search/[collection]) §4, §7, §8

Business Rationale: Prevents invalid sort values from reaching the Shopify API, ensuring the page always renders with a valid product ordering even when the URL is manually edited or a link is malformed.

Related Rules: BR-022, BR-023

Testing Implications:


BR-022: Search Results Summary Shown Only with Query

Domain: Search & Filtering Category: Operative Enforcement: Server Criticality: Low

Rule Statement: The search results summary paragraph must only be rendered when a search query (q parameter) is present in the URL.

Conditions:

Validation Details:

Source Evidence: Search (/search) §3, §8

Business Rationale: Avoids displaying a confusing results summary when the user is browsing all products without a search term.

Related Rules: BR-023, BR-024, BR-025

Testing Implications:


BR-023: Zero Search Results Displays No-Results Message

Domain: Search & Filtering Category: Operative Enforcement: Server Criticality: Medium

Rule Statement: When a search query is present and returns zero products, the application must display the message "There are no products that match "<term>"" and must not render a product grid.

Conditions:

Validation Details:

Source Evidence: Search (/search) §3, §8, §10

Business Rationale: Provides clear user feedback when a search returns no results, preventing a confusing blank page.

Related Rules: BR-022, BR-024

Testing Implications:


BR-024: Product Grid Suppressed When No Products

Domain: Search & Filtering Category: Operative Enforcement: Server Criticality: Low

Rule Statement: The product grid must only be rendered when the products array contains at least one item.

Conditions:

Validation Details:

Source Evidence: Search (/search) §3, §8

Business Rationale: Prevents an empty grid container from being rendered, which could produce a confusing blank layout area.

Related Rules: BR-022, BR-023

Testing Implications:


BR-025: Results Count Text Grammatically Pluralized

Domain: Search & Filtering Category: Decision Enforcement: Server Criticality: Low

Rule Statement: The results count label must display "result" (singular) when exactly one product is returned, and "results" (plural) when more than one product is returned.

Conditions:

Validation Details:

Source Evidence: Search (/search) §4, §8

Business Rationale: Maintains grammatically correct UI copy, improving perceived quality of the user interface.

Related Rules: BR-022

Testing Implications:


3.5: Collection Browsing

Description: Rules governing the display of products within a specific Shopify collection on the Search Detail screen.

Screens involved: Search Detail (/search/[collection])


BR-026: Empty Collection Displays No-Products Message

Domain: Collection Browsing Category: Operative Enforcement: Server Criticality: Medium

Rule Statement: When a valid collection exists but contains no products, the application must display the message "No products found in this collection" rather than an empty grid.

Conditions:

Validation Details:

Source Evidence: Search Detail (/search/[collection]) §3, §8, §10

Business Rationale: Provides clear user feedback when a collection exists but has no products, preventing a confusing blank layout.

Related Rules: BR-004, BR-021

Testing Implications:


3.6: Product Display

Description: Rules governing how product content is presented on the Product Detail screen, including image limits, related product behavior, and link prefetching.

Screens involved: Product Detail (/product/[handle])


BR-007: Product Image Gallery Capped at Five Images

Domain: Product Display Category: Structural Enforcement: Server Criticality: Low

Rule Statement: The product image gallery must receive no more than five images, regardless of how many images the product has in Shopify.

Conditions: Not applicable — this cap is applied unconditionally.

Validation Details:

Source Evidence: Product Detail (/product/[handle]) §4, §8

Business Rationale: Not stated in documentation — verify with business stakeholders. [Not documented — WHO: Product owner or front-end team; WHAT: What is the business or UX rationale for capping gallery images at five? Is this a performance constraint, a design decision, or a Shopify API limitation?; WHERE: Insert in the Business Rationale field of BR-007]

Related Rules: BR-008

Testing Implications:


BR-008: Related Products Section Suppressed When Empty

Domain: Product Display Category: Operative Enforcement: Server Criticality: Low

Rule Statement: The Related Products section must not be rendered when getProductRecommendations returns an empty array.

Conditions:

Validation Details:

Source Evidence: Product Detail (/product/[handle]) §5, §8, §10

Business Rationale: Prevents an empty "Related Products" section with a heading but no content from being displayed, maintaining a clean page layout.

Related Rules: BR-007

Testing Implications:


BR-028: Related Product Links Prefetched on Viewport Entry

Domain: Product Display Category: Operative Enforcement: Client Criticality: Low

Rule Statement: Each related product link must be prefetched by Next.js when it enters the viewport.

Conditions: Not applicable — prefetch={true} is set unconditionally on all related product <Link> components.

Validation Details:

Source Evidence: Product Detail (/product/[handle]) §3, §6, §9

Business Rationale: Improves perceived navigation performance by preloading related product page data before the user clicks, reducing time-to-interactive for subsequent page loads.

Related Rules: BR-008

Testing Implications:


4. Decision Tables

DT-01: Search Results Display Logic

Related Rules: BR-022, BR-023, BR-024 Hit Policy: Unique

Condition: searchValue present Condition: products.length → Summary Paragraph → Product Grid
No Any Not rendered Not rendered
Yes 0 "There are no products that match "<term>"" Not rendered
Yes > 0 "Showing N result(s) for "<term>"" Rendered
No > 0 Not rendered Rendered

DT-02: SEO Metadata Fallback — Item Detail Page

Related Rules: BR-011, BR-012 Hit Policy: First

Condition: page.seo.title present Condition: page.title present → Metadata Title
Yes Any page.seo.title
No Yes page.title
No No Empty string
Condition: page.seo.description present Condition: page.bodySummary present → Metadata Description
Yes Any page.seo.description
No Yes page.bodySummary
No No Empty string

DT-03: SEO Metadata Fallback — Product Detail Page

Related Rules: BR-015, BR-016, BR-017 Hit Policy: First

Condition: product.seo.title present Condition: product.title present → Metadata Title
Yes Any product.seo.title
No Yes product.title
No No Empty string
Condition: product.seo.description present Condition: product.description present → Metadata Description
Yes Any product.seo.description
No Yes product.description
No No Empty string
Condition: product.featuredImage.url truthy → OpenGraph Image
Yes Included in metadata
No Omitted / null

DT-04: SEO Metadata Fallback — Search Detail Page

Related Rules: BR-018, BR-019 Hit Policy: First

Condition: collection.seo.title present Condition: collection.title present → Metadata Title
Yes Any collection.seo.title
No Yes collection.title
No No Empty string
Condition: collection.seo.description present Condition: collection.description present → Metadata Description
Yes Any collection.seo.description
No Yes collection.description
No No "${collection.title} products"

DT-05: Product Availability in Structured Data

Related Rules: BR-009 Hit Policy: Unique

Condition: product.availableForSale → JSON-LD offers.availability
true "https://schema.org/InStock"
false "https://schema.org/OutOfStock"

5. Validation Rules Summary

Rule ID Field / Input Validation Type Constraint Error Message / Behavior
BR-002 params.page (URL segment) Custom Must resolve to an existing Shopify page via getPage notFound() called → Next.js 404 page rendered
BR-003 params.handle (URL segment) Custom Must resolve to an existing Shopify product via getProduct notFound() called → Next.js 404 page rendered
BR-004 params.collection (URL segment) Custom Must resolve to an existing Shopify collection via getCollection notFound() called → Next.js 404 page rendered
BR-021 searchParams.sort (query parameter) Custom Must match a slug in the sorting constants array Silent fallback to defaultSort; no user-facing error
BR-005 product.tags array Custom Checked for presence of HIDDEN_PRODUCT_TAG noindex, nofollow directives set in metadata; no user-facing error

6. Calculation Rules Summary

Rule ID Output Formula / Logic Inputs Precision / Rounding
BR-025 resultsText label products.length > 1 ? "results" : "result" products.length (integer) Not applicable
BR-027 Formatted date string new Intl.DateTimeFormat(undefined, { year: "numeric", month: "long", day: "numeric" }).format(new Date(page.updatedAt)) page.updatedAt (ISO 8601 string) Not applicable — locale-formatted string output
BR-005 indexable boolean !product.tags.includes(HIDDEN_PRODUCT_TAG) product.tags (string array), HIDDEN_PRODUCT_TAG (string constant) Not applicable
BR-007 Gallery images array product.images.slice(0, 5).map(({ url: src, altText }) => ({ src, altText })) product.images array Not applicable — array truncation
BR-021 { sortKey, reverse } pair sorting.find((item) => item.slug === sort) || defaultSort sort query param string, sorting constants array, defaultSort constant Not applicable

7. Rule Dependency Map

Rule Depends On Type Description
BR-002 BR-001 Prerequisite BR-001 establishes that the route is public; BR-002 applies the only gate (data existence)
BR-003 BR-001 Prerequisite BR-001 establishes that the route is public; BR-003 applies the only gate (data existence)
BR-004 BR-001 Prerequisite BR-001 establishes that the route is public; BR-004 applies the only gate (data existence)
BR-005 BR-003 Prerequisite BR-003 must pass (product must exist) before BR-005 can evaluate the tags array
BR-006 BR-005 Complement BR-005 and BR-006 together define the complete behavior for hidden products: de-indexed but accessible
BR-007 BR-003 Prerequisite Product must exist before image array can be sliced
BR-008 BR-003 Prerequisite Product must exist before recommendations can be fetched
BR-009 BR-003 Prerequisite Product must exist before availability can be evaluated
BR-010 BR-003 Prerequisite Product must exist before price range can be expressed
BR-011 BR-002 Prerequisite Page must exist before SEO metadata can be generated
BR-012 BR-002 Prerequisite Page must exist before SEO metadata can be generated
BR-011 BR-012 Complement Together define the complete SEO metadata fallback for Item Detail pages
BR-015 BR-003 Prerequisite Product must exist before SEO metadata can be generated
BR-016 BR-003 Prerequisite Product must exist before SEO metadata can be generated
BR-015 BR-016 Complement Together define the complete SEO metadata fallback for Product Detail pages
BR-017 BR-003 Prerequisite Product must exist before OpenGraph image can be evaluated
BR-018 BR-004 Prerequisite Collection must exist before SEO metadata can be generated
BR-019 BR-004 Prerequisite Collection must exist before SEO metadata can be generated
BR-018 BR-019 Complement Together define the complete SEO metadata fallback for Search Detail pages
BR-021 BR-022 Prerequisite Sort must be resolved before products are fetched; product fetch result drives summary display
BR-022 BR-023 Refinement BR-023 is a specific case of BR-022 (summary shown with query, zero results)
BR-023 BR-024 Complement BR-023 and BR-024 together define the complete zero-results display behavior
BR-026 BR-004 Prerequisite Collection must exist (BR-004 passed) before empty-collection state can be evaluated
BR-026 BR-021 Prerequisite Sort must be resolved before collection products are fetched
BR-028 BR-008 Prerequisite Related products section must be rendered (BR-008 passed) before prefetch links exist
BR-013 BR-020 Complement Together define the OpenGraph type classification across the two content-type screens
BR-014 BR-013 Prerequisite og:article:published_time and og:article:modified_time are only meaningful when og:type is "article"

8. Gap Analysis

GAP-01: Search Input Sanitization Not Documented at Page Level

Type: Single-Side Enforcement Affected Domain: Search & Filtering Risk Level: Medium Description: The searchValue (from ?q) and collection slug are passed directly to getProducts and getCollectionProducts respectively without any sanitization or validation at the page component level. The documentation states that sanitization is expected to occur within lib/shopify, but this is not confirmed in the provided source. If lib/shopify uses string interpolation rather than parameterized GraphQL variables, injection into the Shopify API query is possible. Recommendation: Confirm that lib/shopify uses parameterized GraphQL variables for all user-supplied inputs. Document the sanitization rule explicitly. If sanitization is absent, add input validation at the page level as a defense-in-depth measure. Related Rules: BR-021


GAP-02: No Maximum Image Count Enforcement Beyond Gallery Cap

Type: Implicit Rule Affected Domain: Product Display Risk Level: Low Description: BR-007 caps the gallery at five images, but there is no documented rule governing the minimum number of images required for a product to be displayed, or what the Gallery component renders when it receives zero images. The behavior for a product with no images is undocumented at the page level. Recommendation: Document the expected behavior when product.images is empty or contains zero items. Verify with the Gallery component implementation whether an empty images array produces a broken layout or a graceful placeholder. Related Rules: BR-007


GAP-03: Hidden Product Tag Value Not Documented

Type: Missing Rule Affected Domain: Content Visibility & Access Control Risk Level: Medium Description: The HIDDEN_PRODUCT_TAG constant is imported from lib/constants and used in BR-005, but its actual string value is not documented in the provided screen documentation. The documentation notes it is "typically 'nextjs-frontend-hidden' or similar." Without knowing the exact value, QA engineers cannot test the rule, and merchandising teams cannot correctly tag products in Shopify. Recommendation: Document the exact string value of HIDDEN_PRODUCT_TAG from lib/constants. [Not documented — WHO: Development team; WHAT: What is the exact string value of the HIDDEN_PRODUCT_TAG constant in lib/constants?; WHERE: Insert in the Validation Details of BR-005 and in the Glossary entry for HIDDEN_PRODUCT_TAG] Related Rules: BR-005, BR-006


GAP-04: Server-Locale Date Formatting May Mismatch User Locale

Type: Implicit Rule Affected Domain: Product Data Integrity Risk Level: Low Description: BR-027 uses undefined as the locale argument to Intl.DateTimeFormat, which resolves to the server's runtime locale rather than the user's browser locale. On a server deployed in a non-English locale (e.g., a Vercel edge node), the date may be formatted in an unexpected language for English-speaking users. The documentation acknowledges this as "a subtle but important distinction" but does not state whether it is intentional. Recommendation: Verify with the product owner whether the date should be formatted in the user's browser locale. If user-locale formatting is desired, the date formatting must be moved to a client component or the locale must be passed from the request context. [Not documented — WHO: Product owner; WHAT: Is server-locale date formatting intentional, or should the date be formatted in the user's browser locale?; WHERE: Insert in the Business Rationale field of BR-027] Related Rules: BR-027


GAP-05: Array-Valued Query Parameters Not Guarded

Type: Edge Case Affected Domain: Search & Filtering Risk Level: Medium Description: Both the Search and Search Detail pages cast searchParams as { [key: string]: string }, suppressing TypeScript's awareness that values could be string[] or undefined. If a URL contains repeated parameters (e.g., ?q=a&q=b or ?sort=price-asc&sort=title-asc), the runtime behavior is undefined — the cast does not protect against receiving an array where a string is expected. This could produce unexpected behavior in getProducts or getCollectionProducts. Recommendation: Add runtime validation to confirm that q and sort are scalar strings before use. Replace the unsafe type cast with explicit extraction logic (e.g., Array.isArray(q) ? q[0] : q). Related Rules: BR-021, BR-022


GAP-06: JSON-LD Script Tag XSS Not Fully Mitigated

Type: Missing Rule Affected Domain: Product Data Integrity Risk Level: High Description: The Product Detail page injects JSON-LD structured data via dangerouslySetInnerHTML={{ __html: JSON.stringify(productJsonLd) }}. While JSON.stringify escapes characters that break JSON string context, it does not escape </script> sequences, which could allow a Shopify-sourced product title or description containing </script><script> to break out of the script tag and inject arbitrary HTML. The documentation acknowledges this risk explicitly. Recommendation: Use a JSON serializer that escapes <, >, and & characters within string values (e.g., replacing < with \u003c, > with \u003e, & with \u0026) before injecting into the script tag. This is a known best practice for server-rendered JSON-LD. [Not documented — WHO: Development team; WHAT: Has a safe JSON serializer been implemented for JSON-LD injection, or is raw JSON.stringify still in use?; WHERE: Insert in the Validation Details of a new rule to be added for JSON-LD sanitization] Related Rules: BR-009, BR-010


GAP-07: Missing featuredImage Null Guard in JSON-LD

Type: Edge Case Affected Domain: Product Data Integrity Risk Level: High Description: The Product Detail page accesses product.featuredImage.url directly in the JSON-LD block without a null guard. The documentation notes: "if featuredImage is undefined, this would throw a runtime error." While BR-017 documents a null guard for the OpenGraph metadata block, no equivalent guard is documented for the JSON-LD block. A product without a featuredImage would cause a server-side runtime error, likely resulting in a 500 response. Recommendation: Add a null guard (product.featuredImage?.url) in the JSON-LD construction block, consistent with the OpenGraph metadata handling. This is a defect risk, not merely a gap. Related Rules: BR-017, BR-009


GAP-08: No Error Boundary on RelatedProducts or Gallery

Type: Missing Rule Affected Domain: Product Display Risk Level: Medium Description: Neither the RelatedProducts component nor the Gallery/ProductDescription Suspense wrappers include React Error Boundaries. An unhandled error in any of these components would propagate to the nearest Next.js error boundary (error.tsx), potentially taking down the entire product detail page rather than gracefully degrading the affected section. No rule governing partial failure behavior is documented. Recommendation: Define a business rule specifying the expected behavior when RelatedProducts or Gallery fails to render (e.g., "If the Related Products section fails to load, the main product card must still render"). Implement React Error Boundaries around these sections to enforce partial failure isolation. Related Rules: BR-008, BR-007


GAP-09: getPage Called Twice Per Request

Type: Implicit Rule Affected Domain: SEO & Metadata Risk Level: Low Description: On the Item Detail screen, getPage is called independently in both generateMetadata and the Page component, resulting in two API calls per request unless Next.js's fetch deduplication coalesces them. The documentation notes this behavior but does not confirm whether deduplication is active. If deduplication is not active (e.g., if getPage uses a non-fetch-based HTTP client), this doubles the Shopify API load per page request and could contribute to rate limiting. Recommendation: Confirm whether Next.js fetch deduplication is active for getPage calls. [Not documented — WHO: Development team; WHAT: Does lib/shopify's getPage use the native fetch API (which Next.js deduplicates) or a custom HTTP client? Is request deduplication confirmed to be active?; WHERE: Insert in the Integration Points section of the Item Detail screen documentation and note in GAP-09] Related Rules: BR-011, BR-012


GAP-10: Empty Page Title Not Guarded

Type: Edge Case Affected Domain: Content Visibility & Access Control Risk Level: Low Description: The Item Detail page renders page.title directly in an <h1> element without checking whether the title is empty. If a Shopify page has an empty title, an empty <h1> is rendered. No validation rule or fallback is documented for this case. Similarly, if page.title is empty and page.seo.title is also empty, the metadata title will be empty. Recommendation: Define a rule specifying the minimum content requirements for a renderable page (e.g., "A page must have a non-empty title to be rendered"). Add a guard or fallback for empty page.title values. Related Rules: BR-002, BR-011


9. Glossary

9.1: Business Concepts

Term Definition in this context
Collection A Shopify concept representing a named group of products (e.g., "Summer Sale", "Accessories"). Collections have a handle (URL-friendly slug), title, description, and SEO metadata. Used as the route parameter for the Search Detail screen.
Collection handle The URL-safe identifier for a Shopify collection, used as the [collection] route parameter (e.g., "mens-shirts"). Must match an existing Shopify collection or the page returns 404.
Page handle A URL-safe string identifier for a Shopify CMS page (e.g., about, privacy-policy). Used as both the URL segment and the Shopify API lookup key on the Item Detail screen.
Product handle A URL-safe, human-readable string identifier for a Shopify product (e.g., classic-white-tee). Unique per product, set in Shopify admin. Used as the route parameter on the Product Detail screen.
availableForSale A Shopify boolean field on a product indicating whether any variant of the product is currently purchasable. Used to determine the Schema.org availability value in JSON-LD structured data.
featuredImage The primary/hero image of a Shopify product, used for OpenGraph metadata and JSON-LD. Distinct from the full images array.
HIDDEN_PRODUCT_TAG A string constant (from lib/constants) used as a Shopify product tag to mark products that should not be indexed by search engines. Products with this tag receive noindex, nofollow metadata directives but remain accessible via direct URL.
priceRange A Shopify object containing minVariantPrice and maxVariantPrice, each with amount (string) and currencyCode (ISO 4217 string). Represents the price spread across all variants of a product.
productRecommendations Shopify's algorithmic related-product suggestions, returned by the productRecommendations Storefront API query given a product ID. Used to populate the Related Products section on the Product Detail screen.
page.body The full HTML content of a Shopify CMS page, as returned by the Storefront API. Contains merchant-authored rich text rendered as HTML by the Prose component.
page.bodySummary A plain-text excerpt or summary of the Shopify page body, used as a fallback for SEO meta description when no explicit SEO description is set.
page.seo An optional Shopify object containing merchant-specified SEO overrides: title and description. Takes precedence over the page's default title and body summary in metadata generation.
SEO metadata Shopify resources (pages, products, collections) can have dedicated SEO title and description fields separate from their display title/description. These are preferred for <head> metadata when present.

9.2: Rule Terminology

Term Definition in this context
Structural rule A BABOK rule category describing a constraint on data or state — what must always be true about an entity or relationship. Expressed as an invariant.
Operative rule A BABOK rule category describing a constraint on process or action — what must happen or must not happen under specified conditions. Expressed as a behavioral requirement.
Decision rule A BABOK rule category describing a condition-based outcome — if a set of conditions is true, then a specific result must follow. Expressed as a conditional.
Hit Policy A DMN v1.5 concept defining how a decision table resolves when multiple rows match: Unique (only one row can match), First (first matching row wins), Any (all matching rows give the same result), Collect (all matching rows are applied).
Enforcement point Where a rule is evaluated and enforced: Client (browser/UI), Server (API/backend), or Both.
Criticality The severity of impact if a rule is violated: Critical (data corruption or security breach), High (broken workflow), Medium (degraded user experience), Low (cosmetic or minor).

9.3: Domain Terms

Term Definition in this context
AggregateOffer A Schema.org type used in JSON-LD to represent a product with multiple price points (variants), specifying both highPrice and lowPrice. Used in the Product Detail JSON-LD block.
defaultSort A constant from lib/constants defining the fallback sort configuration used when no valid sort query parameter is present. Defines the default product ordering for Search and Search Detail screens.
generateMetadata A Next.js App Router special export from a page file that runs server-side to produce <head> metadata (title, description, robots, OpenGraph tags) for a route.
getCollection A function in lib/shopify that queries the Shopify Storefront GraphQL API for a single Collection resource by its handle. Called during metadata generation on the Search Detail screen.
getCollectionProducts A function in lib/shopify that queries the Shopify Storefront GraphQL API for all products within a specified collection, accepting collection, sortKey, and reverse parameters.
getPage A function in lib/shopify that queries the Shopify Storefront GraphQL API for a single Page resource by its handle. Called on the Item Detail screen.
getProduct A function in lib/shopify that queries the Shopify Storefront GraphQL API for a single Product resource by its handle. Called on the Product Detail screen.
getProductRecommendations A function in lib/shopify that queries the Shopify Storefront API for algorithmically generated product recommendations given a product ID. Called by the RelatedProducts component.
getProducts A function in lib/shopify that queries the Shopify Storefront GraphQL API for a list of products, accepting sortKey, reverse, and query parameters. Called on the Search screen.
JSON-LD JSON Linked Data — a structured data format embedded in a <script type="application/ld+json"> tag, used by search engines to understand page content for rich results (e.g., product price, availability, images in Google Shopping).
notFound() A Next.js App Router utility function that, when called, halts rendering and triggers the nearest not-found.tsx boundary or the default 404 response. Used as the data-existence gate on Item Detail, Product Detail, and Search Detail screens.
Open Graph (og:) A metadata protocol used by social platforms (Facebook, LinkedIn, Slack, etc.) to generate rich link previews. Set via openGraph in Next.js Metadata.
Prose A custom component that applies typographic styling to raw HTML content. Renders page.body from Shopify using dangerouslySetInnerHTML on the Item Detail screen.
searchValue The value of the q URL query parameter on the Search screen; the keyword string the user searched for. Drives both the product query and the results summary display.
Shopify Storefront API The GraphQL API provided by Shopify that allows headless storefronts to query product, collection, cart, and checkout data. The underlying data source for all product and content data in this application.
sorting An array of sort option objects defined in lib/constants, each containing a slug (URL-friendly identifier), sortKey (Shopify API enum), and reverse (boolean). Maps user-facing sort options to Shopify API parameters.
sortKey A Shopify Storefront API enum value (e.g., PRICE, TITLE, BEST_SELLING) that determines the field by which products are sorted in a GraphQL query.
reverse A boolean passed to the Shopify Storefront API indicating whether the sort order should be reversed (descending). Combined with sortKey to express full sort intent.
React Server Component (RSC) A React component that renders exclusively on the server, sending HTML to the client with no client-side JavaScript bundle for the component itself. All five documented page components are RSCs.
Suspense React's built-in component for declarative loading states, enabling streaming SSR in Next.js App Router. Used on the Product Detail screen to wrap Gallery and ProductDescription.

Business Rules Assessment — Commerce Application — April 2026 Generated by DocAgent — automated codebase documentation analysis. Subject matter expert review is recommended before distribution.