# Base price is correctly set and numeric

- **Pattern:** `ab-001118` (`ecommerce-catalog.product-data.base-price-valid`)
- **Severity:** critical
- **Lifecycle:** active
- **Last modified:** 2026-04-18
- **Canonical URL:** https://auditbuffet.com/patterns/ab-001118
- **License:** CC-BY-4.0 — attribute to AuditBuffet Pattern Catalog (https://auditbuffet.com/patterns/ab-001118)

## Why it matters

Price 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.

## Severity rationale

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.

## Remediation

Use `Decimal` in `prisma/schema.prisma` (not `Float`, which has floating-point precision loss, and not `String`) and enforce `price > 0` validation in `src/app/api/products/route.ts` before every create or update.

```prisma
model Product {
  id    String  @id @default(cuid())
  price Decimal @db.Decimal(10, 2)
}
```

```ts
if (!price || price <= 0) {
  return Response.json({ error: 'Price must be greater than 0' }, { status: 400 })
}
```

For free products, use a separate `isFree` boolean flag rather than `price = 0` — this makes the intent explicit and prevents accidental zero charges.

## Detection

- **ID:** `base-price-valid`
- **Severity:** `critical`
- **What to look for:** Count all price-related fields in the product schema. Enumerate the data type used (Decimal, Float, Int, String). Check all product creation and update paths in `src/app/api/products/` for price validation logic. Count the number of products in seed data or fixtures that have price <= 0, price = null, or non-numeric price values.
- **Before evaluating:** Extract and quote the price field definition from the product schema (e.g., `price Decimal @db.Decimal(10, 2)` from `prisma/schema.prisma`). Also quote any price validation logic found in API routes.
- **Pass criteria:** The price field is a numeric type (Decimal or Float, not String) in the schema, all products in seed data have price > 0, and at least 1 validation path prevents zero or negative prices. Report: "Price type: [type], X of Y products have valid prices > 0."
- **Fail criteria:** Price is stored as a string type, or products exist with zero or negative prices in seed data, or no validation prevents invalid prices in any product creation/update path.
- **Do NOT pass when:** Price is stored as a Decimal/Float but no validation exists anywhere in the codebase to prevent price = 0 or price < 0 — the type alone is insufficient without validation.
- **Skip (N/A) when:** Never — all products must have a valid price.
- **Cross-reference:** For currency handling and internationalization, the Geo-Readiness audit covers multi-currency support and locale-aware formatting.
- **Cross-reference:** For pricing display accuracy, the Pre-Launch audit covers content correctness and data integrity checks.
- **Cross-reference:** For payment amount validation, the Subscription Compliance audit covers price accuracy in transaction flows.
- **Detail on fail:** `"Price field is stored as String type in prisma/schema.prisma"` or `"2 of 15 products have price = 0 in prisma/seed.ts and no validation in src/app/api/products/route.ts"`
- **Remediation:** Use a numeric type for prices in `prisma/schema.prisma` and enforce validation in `src/app/api/products/route.ts`:

  ```prisma
  model Product {
    id String @id @default(cuid())
    price Decimal @db.Decimal(10, 2)
  }
  ```

  ```ts
  if (price <= 0) {
    throw new Error('Price must be greater than 0')
  }
  ```

---

## External references

- cwe CWE-20
- iso-25010 functional-correctness

Taxons: data-integrity

HTML version: https://auditbuffet.com/patterns/ab-001118
