Category taxonomy uses controlled vocabulary, not freeform text
Why it matters
Free-text categories produce Restaurant, restaurant, Restaraunt, and Food as four distinct buckets for the same concept. Your browse pages fragment, faceted filters break, sitemaps balloon with near-duplicate URLs that Google treats as keyword cannibalization, and analytics reports become impossible to trust. Once inconsistent data lands in the database, deduplication is a manual SQL cleanup job that costs far more than enforcing a controlled vocabulary at submission time. Schema.org Category emitters also require stable enum values.
Severity rationale
High because free-text taxonomies fragment browse pages, break filters, and create SEO cannibalization that worsens with scale.
Remediation
Replace the free-text input with a select backed by a canonical enum or category table, and validate the submitted value against that list on the server. Store categories as a foreign-key reference or a constrained string column so the database rejects rows with values outside the vocabulary. Define the enum in src/lib/taxonomy/categories.ts and import it in both the form and the API handler.
export const CATEGORIES = ['restaurant', 'cafe', 'retail', 'services'] as const
export const CategorySchema = z.enum(CATEGORIES)
Seed a category table with the same values and add a CHECK constraint or FK.
DetectionPro
The detection method for this pattern is part of AuditBuffet Pro.
The full method (what to look for, pass and fail conditions, and how results get reported) ships inside the Listing Data & Schema Audit. The pattern definition, severity rationale, and remediation remain openly licensed under CC-BY-4.0.
Taxons
History
- 2026-04-18·v1.0.0·Initial import from directory-listing-schema·automated