All 20 checks with why-it-matters prose, severity, and cross-references to related audits.
Missing or nullable required fields break every downstream system that depends on them: a product without a name can't be indexed by search engines, a missing price silently renders as $0.00 or crashes checkout, and an absent image produces broken layout holes that erode customer trust. ISO 25010:2011 functional-correctness requires that a system produces correct outputs; a schema that permits null names or prices fails that baseline. CWE-1279 (Improper Preserved Integrity of Hardware Configuration) maps to this class of structural omission — when the data model doesn't enforce what the business treats as mandatory, inconsistencies accumulate across catalog, cart, and fulfillment.
Why this severity: High because missing required fields produce silent data corruption that propagates to checkout, search indexes, and fulfillment — defects visible to customers before they're visible to developers.
ecommerce-catalog.product-data.required-fieldsSee full patternWithout a database-level primary key uniqueness constraint, two concurrent product creation requests can produce duplicate IDs — a race condition that corrupts order references, inventory lookups, and analytics joins. Application-level uniqueness checks (checking whether a record exists before inserting) cannot close this window: two simultaneous requests both read zero rows, both proceed to insert, and both succeed. CWE-694 (Use of Multiple Resources with Duplicate Identifier) and ISO 25010:2011 functional-correctness both flag this: duplicate product IDs cause order-to-product joins to return wrong results, cascade deletes to hit unintended rows, and audit logs to become unreliable.
Why this severity: Critical because duplicate product IDs corrupt order records, inventory counts, and revenue reporting — damage that spreads silently and is difficult to reverse once orders reference the wrong product.
ecommerce-catalog.product-data.unique-idsSee full patternProducts without a category assignment become invisible to browsing and filtering — they exist in the database but can't be discovered through any navigation path other than direct search. Beyond UX, ISO 25010:2011 functional-correctness treats uncategorized products as broken catalog behavior: the product is present but unreachable. A nullable `categoryId` foreign key means every product creation path in the codebase can skip assignment, and there's no audit trail for which products were left uncategorized. At scale, this creates catalog rot: orphaned products accumulate, promotional campaigns miss items, and inventory counts diverge from what customers see.
Why this severity: High because uncategorized products disappear from browse and filter paths, making inventory effectively invisible to customers navigating the catalog — a silent revenue leak.
ecommerce-catalog.product-data.category-assignmentSee full patternEmpty or placeholder product descriptions ship straight to production pages, tanking organic search rankings and leaving shoppers with no signal to convert. Search engines down-rank thin-content product pages, and customers abandon carts when copy reads like 'Lorem ipsum' or 'TBD'. This is a placeholder-hygiene and content-integrity failure that erodes trust, inflates return rates from under-informed purchases, and directly reduces conversion on every affected SKU.
Why this severity: Low because the defect degrades SEO and conversion gradually rather than exposing data or breaking checkout.
ecommerce-catalog.product-data.description-qualitySee full patternProducts without images convert at dramatically lower rates — multiple e-commerce studies place the drop at 30–60% versus imaged listings. Beyond conversion, storing images as local filesystem paths (e.g., `/Users/dev/photos/`) means images resolve on the developer's machine and return 404s in every other environment: staging, production, and CI. ISO 25010:2011 functional-correctness requires the system to behave correctly across environments, not just locally. A schema that only supports a single image string also locks out gallery experiences and prevents future migration to multi-image CDN storage without a schema change.
Why this severity: High because products missing images or referencing local filesystem paths display broken UI in production, directly reducing catalog usability and purchase conversion.
ecommerce-catalog.product-data.image-presenceSee full patternPrice stored as a string type (`VARCHAR`, TypeScript `string`) bypasses all numeric comparison operators: sorting by price returns lexicographic order (`'9' > '100'`), and arithmetic in checkout produces `NaN` or `'$50' + '$10' = '$50$10'`. CWE-20 (Improper Input Validation) applies when the schema accepts price values that the business logic cannot safely process. A zero or negative price — even for a free product — creates a Stripe charge for $0 or triggers a refund flow, and no validation to prevent it means a data entry error or API misuse propagates directly to customer receipts and revenue reports.
Why this severity: Critical because a string-typed or unvalidated price field corrupts sort order, arithmetic, and payment charges — defects that appear in customer invoices and financial reporting.
ecommerce-catalog.product-data.base-price-validSee full patternVariant options stored as free-form strings (`'medium'`, `'Med'`, `'M'`) for the same logical value produce duplicate facets in filters, inconsistent add-to-cart payloads, and inventory mismatches when orders reference `'M'` but the stock record uses `'Medium'`. ISO 25010:2011 functional-correctness requires consistent behavior across the same logical input. Without an enum or lookup table, every new developer who touches the product creation form can introduce a new spelling, and there's no schema-level enforcement to catch it. Filter UIs built on free-form strings show three separate size options when there should be one.
Why this severity: High because uncontrolled variant option strings produce inventory mismatches, broken filters, and add-to-cart failures when the selected string doesn't exactly match a database record.
ecommerce-catalog.variant-pricing.variant-options-definedSee full patternDuplicate SKUs break every system that uses SKU as a lookup key: warehouse management, shipping label generation, return processing, and analytics attribution. CWE-694 (Use of Multiple Resources with Duplicate Identifier) applies directly — two variants sharing `SHIRT-RED-M` means a barcode scan on the warehouse floor resolves ambiguously, order fulfillment picks the wrong record, and return lookups return both variants. Without a database-level `UNIQUE` constraint, application-level deduplication checks are vulnerable to race conditions under concurrent insertion — two simultaneous product imports can both pass validation and both write the same SKU.
Why this severity: High because duplicate SKUs cause warehouse fulfillment ambiguity, incorrect return lookups, and broken order-to-variant joins that corrupt inventory counts.
ecommerce-catalog.variant-pricing.unique-skuSee full patternWithout server-side variant combination validation, a customer can construct a POST request to `src/app/api/cart/route.ts` with any arbitrary `size` and `color` values — including combinations that have no matching variant in the database. The cart then references a phantom record, checkout fails at payment time (or succeeds and fulfillment finds nothing to ship), and the error appears only after the customer has already paid. OWASP A03 (Injection) covers this class of untrusted input: the server must not act on client-supplied option values without confirming they map to a real record. Client-side filtering alone can be bypassed with `curl` in under ten seconds.
Why this severity: High because phantom variant combinations reach checkout and either produce fulfillment failures after payment or expose inventory state that the UI was meant to hide from the customer.
ecommerce-catalog.variant-pricing.variant-combination-validationSee full patternWhen a variant has a custom price but the display and cart always use the base product price, customers see one price on the listing and are charged a different amount at checkout — or variants intended to cost more (e.g., XL size surcharge) are sold at the base price, creating a revenue shortfall on every sale of that variant. ISO 25010:2011 functional-correctness requires that price-affecting selections are reflected consistently across all display and calculation contexts. A product page showing $29.99 and a cart showing $24.99 erodes trust even when the error favors the customer.
Why this severity: High because ignoring variant prices causes customers to be charged the wrong amount, producing either customer complaints when overcharged or silent revenue loss when undercharged.
ecommerce-catalog.variant-pricing.variant-price-overrideSee full patternA sale price equal to or greater than the base price (`salePrice >= basePrice`) is a deceptive pricing display: the customer sees a crossed-out "original" price that is lower than or equal to the "sale" price. The FTC Act prohibits deceptive pricing, and several state consumer protection statutes specifically require that a reference price must reflect a genuine prior offer. CWE-20 (Improper Input Validation) covers this at the technical layer — the API accepts a logically invalid price relationship with no rejection. Even without legal exposure, a visible sale price of $60 crossed out next to a regular price of $50 destroys customer trust immediately.
Why this severity: Medium because the business impact — deceptive pricing display and potential FTC consumer protection exposure — requires authenticated admin access to trigger, limiting blast radius but not eliminating it.
ecommerce-catalog.variant-pricing.sale-price-validSee full patternIncorrect discount arithmetic produces wrong prices in every context where the formula runs — cart totals, checkout confirmations, order emails, and refund calculations. The canonical bug: subtracting `percentOff` as a dollar amount instead of a fraction (charging `$100 - 20 = $80` when the intent is `$100 × 0.80 = $80` — those happen to be equal, masking the bug until `10% off $50` yields `$50 - 10 = $40` instead of `$45`). A fixed discount that allows negative final prices means a `$200 off` coupon on a `$150 product` produces a `-$50` cart that Stripe rejects or, worse, creates a refund. ISO 25010:2011 maintainability is the external mapping — calculation logic must be testable and auditable.
Why this severity: Low because incorrect discount logic is detectable before release via manual testing, affects a bounded set of promotional transactions, and does not expose a security vector.
ecommerce-catalog.variant-pricing.discount-logicSee full patternA product schema without a `stock` field, or with a nullable `stock` that defaults to `null`, means the application has no authoritative source for inventory state. Every in-stock/out-of-stock display becomes a guess, overselling becomes possible on the first order, and inventory reports return `NULL` aggregates that silently break dashboards. ISO 25010:2011 functional-correctness requires correct outputs; a stock value of `null` produces neither "in stock" nor "out of stock" — it produces an error or a wrong assumption depending on how `null` is coerced in the display layer. Tracking stock is not optional for e-commerce.
Why this severity: High because an absent or nullable stock field makes overselling possible on every order and renders all inventory reporting unreliable from the first data row.
ecommerce-catalog.inventory.stock-initializedSee full patternStock decrement outside a database transaction is a textbook race condition: two simultaneous order requests both read `stock = 1`, both pass the availability check, both write `stock = 0`, and one physical item ships twice. CWE-362 (Concurrent Execution Using Shared Resource with Improper Synchronization) names this exact failure. At low traffic the window is small but non-zero; at peak sale traffic (Black Friday, flash sales) it becomes near-certain. ISO 25010:2011 fault-tolerance requires the system to handle concurrent requests correctly — a separate `findUnique` + `update` pattern fails this at the architecture level, not the implementation level.
Why this severity: Critical because a race condition in stock decrement causes confirmed orders for items that don't exist, resulting in fulfillment failures and customer refund obligations that grow proportionally with traffic.
ecommerce-catalog.inventory.stock-decrement-on-orderSee full patternAn "Add to Cart" button that remains active on a product with `stock = 0` lets customers complete a purchase for an item that cannot be fulfilled. The failure appears at shipping time, not at checkout, meaning the customer has already paid and must wait for a refund. For schema.org structured data (schema-org Offer), `availability: OutOfStock` is a required signal for Google Shopping to suppress the listing from purchase-intent results — without it, out-of-stock products appear in paid shopping placements and generate click costs with no conversion. The Accessibility Fundamentals audit requires disabled interactive elements to be visually and semantically distinct, so an always-enabled button also creates an accessibility gap.
Why this severity: High because customers can place orders for zero-stock products, triggering fulfillment failures and refund workflows that cost more to resolve than the original sale was worth.
ecommerce-catalog.inventory.out-of-stock-markingSee full patternWith no low-stock signal, shoppers who would convert under urgency keep browsing and abandon, while a hardcoded threshold of 1 fires too late to move units before the SKU goes dark. The inverse failure — fabricated urgency with no real threshold — draws FTC scrutiny under scarcity-claim rules. Either way, a missing or non-configurable threshold hands revenue back to competitors and blocks the merchandising team from tuning behavior per category.
Why this severity: Low because the impact is conversion-rate loss and merchandising inflexibility, not a security or data-integrity failure.
ecommerce-catalog.inventory.low-stock-warningSee full patternSearch that queries only `name` or is case-sensitive returns empty results for shoppers typing 'red shirt' instead of 'Red Shirt', so the catalog's long tail is effectively invisible. Every zero-result search is an abandoned session and a lost order. Internal search is also a top SEO signal — sites that surface relevant results rank better and earn more crawl budget. Narrow or case-sensitive matching turns a working catalog into a dead end.
Why this severity: Low because users can still browse categories, but every failed query is a direct conversion loss.
ecommerce-catalog.search-discovery.search-relevanceSee full patternFilters that display but do not narrow the list, or that OR across types instead of AND, return products that violate the shopper's explicit constraints — a $0-$50 selection that still shows $120 items destroys trust on the spot. Users correlate broken filters with a broken store and leave. Faceted navigation that ignores query parameters also generates duplicate-content SEO penalties because every filter URL serves the same full catalog.
Why this severity: Medium because broken filters silently break purchase intent across every category page and erode SEO simultaneously.
ecommerce-catalog.search-discovery.filters-workingSee full patternURLs like `/products/clk123abc456` give search engines and humans zero keyword signal, cost rankings on long-tail product queries, and make every shared link look like spam. Competitors using slug-based URLs rank above you for the same inventory. Swapping product platforms or re-seeding the database also breaks every external link because IDs shift, whereas stable slugs survive migrations and preserve the findability equity you already earned.
Why this severity: Low because the catalog still functions, but ID-based URLs permanently suppress organic traffic and link equity.
ecommerce-catalog.search-discovery.seo-friendly-urlsSee full patternGoogle and Bing use schema.org Product and Offer structured data to populate rich results — price, availability, and review stars displayed directly in search results. Without `application/ld+json` markup on product pages, listings appear as plain blue links competing against structured cards from competitors. For Google Shopping specifically, the schema.org `Offer.availability` field controls whether a product appears in shopping results at all. The schema-org Offer spec also feeds into AI shopping assistants that extract product data for recommendations — pages without structured data are invisible to this emerging discovery channel.
Why this severity: Info because missing schema.org markup reduces search result richness and AI discoverability but does not break any user-facing functionality or expose a security surface.
ecommerce-catalog.search-discovery.schema-org-markupSee full patternRun this audit in your AI coding tool (Claude Code, Cursor, Bolt, etc.) and submit results here for scoring and benchmarks.
Open Catalog & Product Logic Audit